tests: add dummy plugin for daemon unit tests

The TestSuite plugin contains audio, video and chat handlers to
support toggling/untoogling tests.

GitLab: https://git.jami.net/savoirfairelinux/jami-daemon/-/issues/745

Change-Id: I45f55127443a5c904b89066b6fe1ca102d37e361
diff --git a/AutoAnswer/BotPeerChatSubscriber.h b/AutoAnswer/BotPeerChatSubscriber.h
index cac463b..70e1964 100644
--- a/AutoAnswer/BotPeerChatSubscriber.h
+++ b/AutoAnswer/BotPeerChatSubscriber.h
@@ -46,8 +46,6 @@
                   std::string& peerId,
                   std::map<std::string, std::string>& sendMsg,
                   bool swarm);
-    void setAnswer(const std::string& textAnswer);
-    void setInText(const std::string& inText);
 
 protected:
     // Observer pattern
diff --git a/TestSuite/AudioHandlerTester.cpp b/TestSuite/AudioHandlerTester.cpp
new file mode 100644
index 0000000..4b6b73a
--- /dev/null
+++ b/TestSuite/AudioHandlerTester.cpp
@@ -0,0 +1,89 @@
+/**
+ *  Copyright (C) 2020-2021 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, write to the Free Software
+ *  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301 USA.
+ */
+
+#include "AudioHandlerTester.h"
+
+#include "pluglog.h"
+#include <string_view>
+
+const char sep = separator();
+const std::string TAG = "AudioHandlerTester";
+
+#define NAME "AudioHandlerTester"
+
+namespace jami {
+
+AudioHandlerTester::AudioHandlerTester(std::string&& datapath)
+    : datapath_ {datapath}
+{
+    setId(datapath_);
+    mAS = std::make_shared<AudioSubscriberTester>();
+}
+
+void
+AudioHandlerTester::notifyAVFrameSubject(const StreamData& data, jami::avSubjectPtr subject)
+{
+    if (!mAS)
+        return;
+    std::ostringstream oss;
+    std::string_view direction = data.direction ? "Receive" : "Preview";
+    oss << "NEW SUBJECT: [" << data.id << "," << direction << "]" << std::endl;
+    bool preferredStreamDirection = false; // false for output; true for input
+    oss << "preferredStreamDirection " << preferredStreamDirection << std::endl;
+    if (data.type == StreamType::audio && !data.direction
+        && data.direction == preferredStreamDirection) {
+        subject->attach(mAS.get()); // your image
+        oss << "got my sent audio attached" << std::endl;
+        attached_ = '1';
+    } else if (data.type == StreamType::audio && data.direction
+               && data.direction == preferredStreamDirection) {
+        subject->attach(mAS.get()); // the image you receive from others on the call
+        oss << "got received audio attached" << std::endl;
+        attached_ = '1';
+    }
+
+    Plog::log(Plog::LogPriority::INFO, TAG, oss.str());
+}
+
+std::map<std::string, std::string>
+AudioHandlerTester::getCallMediaHandlerDetails()
+{
+    return {{"name", NAME},
+            {"iconPath", datapath_ + sep + "icon.svg"},
+            {"pluginId", id()},
+            {"attached", attached_},
+            {"dataType", "0"}};
+}
+
+void
+AudioHandlerTester::detach()
+{
+    attached_ = '0';
+    mAS->detach();
+}
+
+AudioHandlerTester::~AudioHandlerTester()
+{
+    std::ostringstream oss;
+    oss << " ~AudioHandlerTester from TestSuite Plugin" << std::endl;
+    Plog::log(Plog::LogPriority::INFO, TAG, oss.str());
+    detach();
+}
+} // namespace jami
diff --git a/TestSuite/AudioHandlerTester.h b/TestSuite/AudioHandlerTester.h
new file mode 100644
index 0000000..c31a430
--- /dev/null
+++ b/TestSuite/AudioHandlerTester.h
@@ -0,0 +1,50 @@
+/**
+ *  Copyright (C) 2020-2021 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, write to the Free Software
+ *  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301 USA.
+ */
+
+#pragma once
+
+#include "AudioSubscriberTester.h"
+
+#include "plugin/jamiplugin.h"
+#include "plugin/mediahandler.h"
+
+using avSubjectPtr = std::weak_ptr<jami::Observable<AVFrame*>>;
+
+namespace jami {
+
+class AudioHandlerTester : public CallMediaHandler
+{
+public:
+    AudioHandlerTester(std::string&& dataPath);
+    ~AudioHandlerTester();
+
+    virtual void notifyAVFrameSubject(const StreamData& data, avSubjectPtr subject) override;
+    virtual std::map<std::string, std::string> getCallMediaHandlerDetails() override;
+    virtual void detach() override;
+    virtual void setPreferenceAttribute(const std::string& key, const std::string& value) override {}
+    virtual bool preferenceMapHasKey(const std::string& key) override { return false; }
+
+    std::shared_ptr<AudioSubscriberTester> mAS{};
+
+private:
+    const std::string datapath_;
+    std::string attached_ {'0'};
+};
+} // namespace jami
diff --git a/TestSuite/AudioSubscriberTester.cpp b/TestSuite/AudioSubscriberTester.cpp
new file mode 100644
index 0000000..52f4afb
--- /dev/null
+++ b/TestSuite/AudioSubscriberTester.cpp
@@ -0,0 +1,65 @@
+/**
+ *  Copyright (C) 2020-2021 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, write to the Free Software
+ *  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301 USA.
+ */
+
+#include "AudioSubscriberTester.h"
+
+#include <pluglog.h>
+
+const std::string TAG = "AudioHandlerTester";
+const char sep = separator();
+
+namespace jami {
+
+AudioSubscriberTester::~AudioSubscriberTester()
+{
+    std::ostringstream oss;
+    oss << "~AudioSubscriberTester" << std::endl;
+    Plog::log(Plog::LogPriority::INFO, TAG, oss.str());
+}
+
+void
+AudioSubscriberTester::attached(Observable<AVFrame*>* observable)
+{
+    std::ostringstream oss;
+    oss << "::Attached ! " << std::endl;
+    Plog::log(Plog::LogPriority::INFO, TAG, oss.str());
+    observable_ = observable;
+}
+
+void
+AudioSubscriberTester::detached(Observable<AVFrame*>*)
+{
+    observable_ = nullptr;
+    std::ostringstream oss;
+    oss << "::Detached()" << std::endl;
+    Plog::log(Plog::LogPriority::INFO, TAG, oss.str());
+}
+
+void
+AudioSubscriberTester::detach()
+{
+    if (observable_) {
+        std::ostringstream oss;
+        oss << "::Calling detach()" << std::endl;
+        Plog::log(Plog::LogPriority::INFO, TAG, oss.str());
+        observable_->detach(this);
+    }
+}
+} // namespace jami
diff --git a/TestSuite/AudioSubscriberTester.h b/TestSuite/AudioSubscriberTester.h
new file mode 100644
index 0000000..83e1bfa
--- /dev/null
+++ b/TestSuite/AudioSubscriberTester.h
@@ -0,0 +1,49 @@
+/**
+ *  Copyright (C) 2020-2021 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, write to the Free Software
+ *  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301 USA.
+ */
+
+#pragma once
+
+extern "C" {
+#include <libavutil/frame.h>
+}
+#include <observer.h>
+
+namespace jami {
+
+class AudioSubscriberTester : public Observer<AVFrame*>
+{
+public:
+    AudioSubscriberTester() {}
+    ~AudioSubscriberTester();
+
+    virtual void update(Observable<AVFrame*>*, AVFrame* const&) override {}
+    virtual void attached(Observable<AVFrame*>*) override;
+    virtual void detached(Observable<AVFrame*>*) override;
+
+    void detach();
+
+private:
+    // Observer pattern
+    Observable<AVFrame*>* observable_{};
+
+    // Data
+    std::string path_;
+};
+} // namespace jami
diff --git a/TestSuite/CMakeLists.txt b/TestSuite/CMakeLists.txt
new file mode 100644
index 0000000..51f516f
--- /dev/null
+++ b/TestSuite/CMakeLists.txt
@@ -0,0 +1,91 @@
+cmake_minimum_required(VERSION 3.10)
+
+# set the project name
+set (ProjectName TestSuite)
+set (Version 1.0.0)
+
+project(${ProjectName} VERSION ${Version})
+
+set (DAEMON ${PROJECT_SOURCE_DIR}/../../daemon)
+set (JPL_FILE_NAME ${ProjectName}.jpl)
+set (DAEMON_SRC ${DAEMON}/src)
+set (CONTRIB_PATH ${DAEMON}/contrib)
+set (PLUGINS_LIB ${PROJECT_SOURCE_DIR}/../lib)
+set (JPL_DIRECTORY ${PROJECT_BINARY_DIR}/jpl)
+set (LIBS_DIR ${PROJECT_SOURCE_DIR}/../contrib/Libs)
+
+if(WIN32)
+    message(OS:\  WINDOWS\ ${CMAKE_SYSTEM_PROCESSOR})
+    if (NOT ${CMAKE_CL_64})
+        message( FATAL_ERROR "\nUse CMake only for x64 Windows" )
+    endif()
+    set (CONTRIB_PLATFORM_CURT x64)
+    set (CONTRIB_PLATFORM ${CONTRIB_PLATFORM_CURT}-windows)
+    set (LIBRARY_FILE_NAME ${ProjectName}.dll)
+    set (FFMPEG ${CONTRIB_PATH}/build/ffmpeg/Build/win32/x64)
+else()
+    message( FATAL_ERROR "\nUse CMake only for Windows! For linux or Android (linux host), use our bash scripts." )
+endif()
+
+message(Building:\   ${ProjectName}\   ${Version})
+message(Build\ path:\ ${PROJECT_BINARY_DIR})
+message(JPL\ assembling\ path:\ ${JPL_DIRECTORY})
+message(JPL\ path:\ ${JPL_DIRECTORY}/../../../build/${ProjectName}/${JPL_FILE_NAME})
+
+set(CMAKE_CXX_STANDARD 17)
+set(CMAKE_CXX_STANDARD_REQUIRED True)
+set(CMAKE_CXX_FLAGS_RELEASE "${CMAKE_CXX_FLAGS_RELEASE} /MT")
+set(CMAKE_CXX_FLAGS_DEBUG "${CMAKE_CXX_FLAGS_DEBUG} /MTd")
+
+set(plugin_SRC AudioHandlerTester.cpp
+               AudioSubscriberTester.cpp
+               VideoHandlerTester.cpp
+               VideoSubscriberTester.cpp
+               ChatHandlerTester.cpp
+               ChatSubscriberTester.cpp
+               main.cpp
+               )
+
+set(plugin_HDR AudioHandlerTester.h
+               AudioSubscriberTester.h
+               VideoHandlerTester.h
+               VideoSubscriberTester.h
+               ChatHandlerTester.h
+               ChatSubscriberTester.h
+               ./../lib/pluglog.h
+               )
+
+add_library(${ProjectName} SHARED ${plugin_SRC}
+                                  ${plugin_HDR}
+                                  )
+
+target_include_directories(${ProjectName} PUBLIC ${PROJECT_BINARY_DIR}
+                                                 ${PROJECT_SOURCE_DIR}
+                                                 ${PLUGINS_LIB}
+                                                 ${DAEMON_SRC}
+                                                 ${CONTRIB_PATH}
+                                                 ${CONTRIB_PATH}/build/fmt/include
+                                                 ${FFMPEG}/include
+                                                 )
+target_link_directories(${ProjectName} PUBLIC ${CONTRIB_PATH}
+                                        ${FFMPEG}/bin
+                                        ${CONTRIB_PATH}/build/fmt/msvc/Release
+                                        )
+
+target_link_libraries(${ProjectName} PUBLIC avutil)
+
+add_custom_command(
+    TARGET ${ProjectName}
+    PRE_BUILD
+    COMMAND python ${PROJECT_SOURCE_DIR}/../SDK/jplManipulation.py --preassemble --plugin=${ProjectName}
+    COMMENT "Assembling Plugin files"
+)
+
+add_custom_command(
+    TARGET ${ProjectName}
+    POST_BUILD
+    COMMAND ${CMAKE_COMMAND} -E copy ${PROJECT_BINARY_DIR}/Release/${ProjectName}.lib ${JPL_DIRECTORY}/lib/${CONTRIB_PLATFORM}
+    COMMAND ${CMAKE_COMMAND} -E copy ${PROJECT_BINARY_DIR}/Release/${LIBRARY_FILE_NAME} ${JPL_DIRECTORY}/lib/${CONTRIB_PLATFORM}
+    COMMAND python ${PROJECT_SOURCE_DIR}/../SDK/jplManipulation.py --assemble --plugin=${ProjectName}
+    COMMENT "Generating JPL archive"
+)
diff --git a/TestSuite/ChatHandlerTester.cpp b/TestSuite/ChatHandlerTester.cpp
new file mode 100644
index 0000000..f1b1907
--- /dev/null
+++ b/TestSuite/ChatHandlerTester.cpp
@@ -0,0 +1,76 @@
+/**
+ *  Copyright (C) 2020-2021 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, write to the Free Software
+ *  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301 USA.
+ */
+
+#include "ChatHandlerTester.h"
+
+#include "pluglog.h"
+
+const char sep = separator();
+const std::string TAG = "ChatHandlerTester";
+
+#define NAME "ChatHandlerTester"
+
+namespace jami {
+
+ChatHandlerTester::ChatHandlerTester(std::string&& dataPath)
+    : datapath_ {dataPath}
+{
+    setId(datapath_);
+    mCS_ = std::make_shared<ChatSubscriberTester>();
+}
+
+void
+ChatHandlerTester::notifyChatSubject(std::pair<std::string, std::string>& subjectConnection,
+                                     chatSubjectPtr subject)
+{
+    if (mCS_ && subjects.find(subject) == subjects.end()) {
+        std::ostringstream oss;
+        oss << "NEW SUBJECT: account = " << subjectConnection.first
+            << " peer = " << subjectConnection.second << std::endl;
+        Plog::log(Plog::LogPriority::INFO, TAG, oss.str());
+        subject->attach(mCS_.get());
+        subjects.insert(subject);
+    }
+}
+
+std::map<std::string, std::string>
+ChatHandlerTester::getChatHandlerDetails()
+{
+    return {{"name", NAME}, {"iconPath", datapath_ + sep + "icon.svg"}, {"pluginId", id()}};
+}
+
+void
+ChatHandlerTester::detach(chatSubjectPtr subject)
+{
+    auto it = subjects.find(subject);
+    if (it != subjects.end()) {
+        subject->detach(mCS_.get());
+        subjects.erase(it);
+    }
+}
+
+ChatHandlerTester::~ChatHandlerTester()
+{
+    const auto copy = subjects;
+    for (const auto& subject : copy) {
+        detach(subject);
+    }
+}
+} // namespace jami
diff --git a/TestSuite/ChatHandlerTester.h b/TestSuite/ChatHandlerTester.h
new file mode 100644
index 0000000..8357ef7
--- /dev/null
+++ b/TestSuite/ChatHandlerTester.h
@@ -0,0 +1,56 @@
+/**
+ *  Copyright (C) 2020-2021 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, write to the Free Software
+ *  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301 USA.
+ */
+
+#pragma once
+
+#include "ChatSubscriberTester.h"
+
+#include "plugin/jamiplugin.h"
+#include "plugin/chathandler.h"
+
+#include <string>
+#include <map>
+#include <memory>
+#include <set>
+
+using chatSubjectPtr = std::shared_ptr<jami::PublishObservable<jami::pluginMessagePtr>>;
+
+namespace jami {
+
+class ChatHandlerTester : public jami::ChatHandler
+{
+public:
+    ChatHandlerTester(std::string&& dataPath);
+    ~ChatHandlerTester();
+
+    void notifyChatSubject(std::pair<std::string, std::string>& subjectConnection,
+                           chatSubjectPtr subject) override;
+    std::map<std::string, std::string> getChatHandlerDetails() override;
+    void detach(chatSubjectPtr subject) override;
+    void setPreferenceAttribute(const std::string& key, const std::string& value) override {}
+    bool preferenceMapHasKey(const std::string& key) override { return false; }
+
+    std::shared_ptr<ChatSubscriberTester> mCS_ {};
+
+private:
+    const std::string datapath_;
+    std::set<chatSubjectPtr> subjects;
+};
+} // namespace jami
diff --git a/TestSuite/ChatSubscriberTester.cpp b/TestSuite/ChatSubscriberTester.cpp
new file mode 100644
index 0000000..7ee5ab5
--- /dev/null
+++ b/TestSuite/ChatSubscriberTester.cpp
@@ -0,0 +1,60 @@
+/**
+ *  Copyright (C) 2020-2021 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, write to the Free Software
+ *  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301 USA.
+ */
+
+#include "ChatSubscriberTester.h"
+#include "pluglog.h"
+
+const std::string TAG = "ChatHandlerTester";
+
+namespace jami {
+
+ChatSubscriberTester::~ChatSubscriberTester()
+{
+    std::ostringstream oss;
+    oss << "~ChatSubscriberTester" << std::endl;
+    Plog::log(Plog::LogPriority::INFO, TAG, oss.str());
+}
+
+void
+ChatSubscriberTester::attached(Observable<pluginMessagePtr>* observable)
+{
+    if (observables_.find(observable) == observables_.end()) {
+        std::ostringstream oss;
+        oss << "::Attached ! " << std::endl;
+        Plog::log(Plog::LogPriority::INFO, TAG, oss.str());
+        observables_.insert(observable);
+        isAttached = true;
+    }
+}
+
+void
+ChatSubscriberTester::detached(Observable<pluginMessagePtr>* observable)
+{
+    auto it = observables_.find(observable);
+    if (it != observables_.end()) {
+        observables_.erase(it);
+        std::ostringstream oss;
+        oss << "::Detached()" << std::endl;
+        Plog::log(Plog::LogPriority::INFO, TAG, oss.str());
+        if (observables_.empty())
+            isAttached = false;
+    }
+}
+} // namespace jami
diff --git a/TestSuite/ChatSubscriberTester.h b/TestSuite/ChatSubscriberTester.h
new file mode 100644
index 0000000..f93e38d
--- /dev/null
+++ b/TestSuite/ChatSubscriberTester.h
@@ -0,0 +1,48 @@
+/**
+ *  Copyright (C) 2020-2021 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, write to the Free Software
+ *  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301 USA.
+ */
+
+#pragma once
+
+#include "observer.h"
+
+#include "plugin/streamdata.h"
+#include "plugin/jamiplugin.h"
+#include "plugin/chathandler.h"
+
+#include <map>
+#include <set>
+
+namespace jami {
+
+class ChatSubscriberTester : public Observer<pluginMessagePtr>
+{
+public:
+    ChatSubscriberTester() {}
+    ~ChatSubscriberTester();
+    virtual void update(Observable<pluginMessagePtr>*, pluginMessagePtr const&) override {}
+    virtual void attached(Observable<pluginMessagePtr>*) override;
+    virtual void detached(Observable<pluginMessagePtr>*) override;
+
+protected:
+    // Observer pattern
+    std::set<Observable<pluginMessagePtr>*> observables_;
+    bool isAttached {false};
+};
+} // namespace jami
diff --git a/TestSuite/VideoHandlerTester.cpp b/TestSuite/VideoHandlerTester.cpp
new file mode 100644
index 0000000..1029161
--- /dev/null
+++ b/TestSuite/VideoHandlerTester.cpp
@@ -0,0 +1,88 @@
+/**
+ *  Copyright (C) 2020-2021 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, write to the Free Software
+ *  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301 USA.
+ */
+
+#include "VideoHandlerTester.h"
+
+#include "pluglog.h"
+#include <string_view>
+
+const char sep = separator();
+const std::string TAG = "VideoHandlerTester";
+
+#define NAME "VideoHandlerTester"
+
+namespace jami {
+
+VideoHandlerTester::VideoHandlerTester(std::string&& datapath)
+    : datapath_ {datapath}
+{
+    setId(datapath_);
+    mVS = std::make_shared<VideoSubscriberTester>();
+}
+
+void
+VideoHandlerTester::notifyAVFrameSubject(const StreamData& data, jami::avSubjectPtr subject)
+{
+    std::ostringstream oss;
+    std::string_view direction = data.direction ? "Receive" : "Preview";
+    oss << "NEW SUBJECT: [" << data.id << "," << direction << "]" << std::endl;
+
+    bool preferredStreamDirection = false; // false for output; true for input
+    oss << "preferredStreamDirection " << preferredStreamDirection << std::endl;
+    if (data.type == StreamType::video && !data.direction
+        && data.direction == preferredStreamDirection) {
+        subject->attach(mVS.get()); // your image
+        oss << "got my sent image attached" << std::endl;
+        attached_ = "1";
+    } else if (data.type == StreamType::video && data.direction
+               && data.direction == preferredStreamDirection) {
+        subject->attach(mVS.get()); // the image you receive from others on the call
+        oss << "got received image attached" << std::endl;
+        attached_ = "1";
+    }
+
+    Plog::log(Plog::LogPriority::INFO, TAG, oss.str());
+}
+
+std::map<std::string, std::string>
+VideoHandlerTester::getCallMediaHandlerDetails()
+{
+    return {{"name", NAME},
+            {"iconPath", datapath_ + sep + "icon.svg"},
+            {"pluginId", id()},
+            {"attached", attached_},
+            {"dataType", "1"}};
+}
+
+void
+VideoHandlerTester::detach()
+{
+    attached_ = "0";
+    mVS->detach();
+}
+
+VideoHandlerTester::~VideoHandlerTester()
+{
+    std::ostringstream oss;
+    oss << " ~VideoHandlerTester from TestSuite Plugin" << std::endl;
+    Plog::log(Plog::LogPriority::INFO, TAG, oss.str());
+    detach();
+}
+} // namespace jami
diff --git a/TestSuite/VideoHandlerTester.h b/TestSuite/VideoHandlerTester.h
new file mode 100644
index 0000000..b5a57e7
--- /dev/null
+++ b/TestSuite/VideoHandlerTester.h
@@ -0,0 +1,50 @@
+/**
+ *  Copyright (C) 2020-2021 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, write to the Free Software
+ *  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301 USA.
+ */
+
+#pragma once
+
+#include "VideoSubscriberTester.h"
+#include "plugin/jamiplugin.h"
+#include "plugin/mediahandler.h"
+
+using avSubjectPtr = std::weak_ptr<jami::Observable<AVFrame*>>;
+
+namespace jami {
+
+class VideoHandlerTester : public jami::CallMediaHandler
+{
+public:
+    VideoHandlerTester(std::string&& dataPath);
+    ~VideoHandlerTester();
+
+    virtual void notifyAVFrameSubject(const StreamData& data, avSubjectPtr subject) override;
+    virtual std::map<std::string, std::string> getCallMediaHandlerDetails() override;
+
+    virtual void detach() override;
+    virtual void setPreferenceAttribute(const std::string& key, const std::string& value) override {}
+    virtual bool preferenceMapHasKey(const std::string& key) override { return false; }
+
+    std::shared_ptr<VideoSubscriberTester> mVS{};
+
+private:
+    const std::string datapath_;
+    std::string attached_ {"0"};
+};
+} // namespace jami
diff --git a/TestSuite/VideoSubscriberTester.cpp b/TestSuite/VideoSubscriberTester.cpp
new file mode 100644
index 0000000..d428a84
--- /dev/null
+++ b/TestSuite/VideoSubscriberTester.cpp
@@ -0,0 +1,66 @@
+/**
+ *  Copyright (C) 2020-2021 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, write to the Free Software
+ *  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301 USA.
+ */
+
+#include "VideoSubscriberTester.h"
+
+#include <pluglog.h>
+#include <stdio.h>
+
+const std::string TAG = "VideoHandlerTester";
+const char sep = separator();
+
+namespace jami {
+
+VideoSubscriberTester::~VideoSubscriberTester()
+{
+    std::ostringstream oss;
+    oss << "~VideoSubscriberTester" << std::endl;
+    Plog::log(Plog::LogPriority::INFO, TAG, oss.str());
+}
+
+void
+VideoSubscriberTester::attached(jami::Observable<AVFrame*>* observable)
+{
+    std::ostringstream oss;
+    oss << "::Attached ! " << std::endl;
+    Plog::log(Plog::LogPriority::INFO, TAG, oss.str());
+    observable_ = observable;
+}
+
+void
+VideoSubscriberTester::detached(jami::Observable<AVFrame*>*)
+{
+    observable_ = nullptr;
+    std::ostringstream oss;
+    oss << "::Detached()" << std::endl;
+    Plog::log(Plog::LogPriority::INFO, TAG, oss.str());
+}
+
+void
+VideoSubscriberTester::detach()
+{
+    if (observable_) {
+        std::ostringstream oss;
+        oss << "::Calling detach()" << std::endl;
+        Plog::log(Plog::LogPriority::INFO, TAG, oss.str());
+        observable_->detach(this);
+    }
+}
+} // namespace jami
diff --git a/TestSuite/VideoSubscriberTester.h b/TestSuite/VideoSubscriberTester.h
new file mode 100644
index 0000000..49d5ca7
--- /dev/null
+++ b/TestSuite/VideoSubscriberTester.h
@@ -0,0 +1,46 @@
+/**
+ *  Copyright (C) 2020-2021 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, write to the Free Software
+ *  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301 USA.
+ */
+
+#pragma once
+
+extern "C" {
+#include <libavutil/frame.h>
+}
+#include <observer.h>
+
+namespace jami {
+
+class VideoSubscriberTester : public jami::Observer<AVFrame*>
+{
+public:
+    VideoSubscriberTester() {}
+    ~VideoSubscriberTester();
+
+    virtual void update(jami::Observable<AVFrame*>*, AVFrame* const&) override {}
+    virtual void attached(jami::Observable<AVFrame*>*) override;
+    virtual void detached(jami::Observable<AVFrame*>*) override;
+
+    void detach();
+
+private:
+    // Observer pattern
+    Observable<AVFrame*>* observable_{};
+};
+} // namespace jami
diff --git a/TestSuite/build.sh b/TestSuite/build.sh
new file mode 100755
index 0000000..881221a
--- /dev/null
+++ b/TestSuite/build.sh
@@ -0,0 +1,267 @@
+#! /bin/bash
+# Build the plugin for the project
+set -e
+export OSTYPE
+ARCH=$(uname -m)
+EXTRAPATH=''
+# Flags:
+
+# -p: number of processors to use
+# -c: Runtime plugin cpu/gpu setting.
+# -t: target platform.
+
+
+if [ -z "${DAEMON}" ]; then
+    DAEMON="./../../daemon"
+    echo "DAEMON not provided, building with ${DAEMON}"
+fi
+
+PLUGIN_NAME="TestSuite"
+JPL_FILE_NAME="${PLUGIN_NAME}.jpl"
+SO_FILE_NAME="lib${PLUGIN_NAME}.so"
+DAEMON_SRC="${DAEMON}/src"
+CONTRIB_PATH="${DAEMON}/contrib"
+PLUGINS_LIB="../lib"
+LIBS_DIR="./../contrib/Libs"
+PLATFORM=$(uname)
+
+if [ "${PLATFORM}" = "Linux" ]; then
+    PLATFORM="linux-gnu"
+    CONTRIB_PLATFORM_CURT=${ARCH}
+    echo "Building with ${PLATFORM}"
+elif [ "${PLATFORM}" = "Darwin" ]; then
+    PLATFORM="darwin"
+    SO_FILE_NAME="lib${PLUGIN_NAME}.dylib"
+    alias nproc='sysctl -n hw.logicalcpu'
+    CONTRIB_PLATFORM_CURT=${ARCH}-apple
+    CONTRIB_PLATFORM_EXTRA=$(uname -r)
+    echo "Building with ${PLATFORM}"
+fi
+
+while getopts t:c:p OPT; do
+  case "$OPT" in
+    t)
+      PLATFORM="${OPTARG}"
+    ;;
+    c)
+      PROCESSOR="${OPTARG}"
+    ;;
+    p)
+    ;;
+    \?)
+      exit 1
+    ;;
+  esac
+done
+
+if [ "${PLATFORM}" = "linux-gnu" ] || [ "${PLATFORM}" = "redhat-linux" ]
+then
+    python3 ./../SDK/jplManipulation.py --preassemble --plugin=${PLUGIN_NAME}
+
+    CONTRIB_PLATFORM=${CONTRIB_PLATFORM_CURT}-${PLATFORM}
+
+    # Compile
+    clang++ -std=c++17 -shared -fPIC \
+    -Wl,-Bsymbolic,-rpath,"\${ORIGIN}" \
+    -Wall -Wextra \
+    -Wno-unused-variable \
+    -Wno-unused-function \
+    -Wno-unused-parameter \
+    -I"." \
+    -I"${DAEMON_SRC}" \
+    -I"${CONTRIB_PATH}/${CONTRIB_PLATFORM}/include" \
+    -I"${PLUGINS_LIB}" \
+    AudioHandlerTester.cpp \
+    AudioSubscriberTester.cpp \
+    VideoHandlerTester.cpp \
+    VideoSubscriberTester.cpp \
+    ChatHandlerTester.cpp \
+    ChatSubscriberTester.cpp \
+    main.cpp \
+    -L"${CONTRIB_PATH}/${CONTRIB_PLATFORM}/lib/" \
+    -l:libavutil.a \
+    -lva \
+    -o "build-local/jpl/lib/${CONTRIB_PLATFORM}/${SO_FILE_NAME}"
+
+elif [ "${PLATFORM}" = "darwin" ]
+then
+    python3 ./../SDK/jplManipulation.py --preassemble --plugin=${PLUGIN_NAME}
+
+    CONTRIB_PLATFORM=${CONTRIB_PLATFORM_CURT}-${PLATFORM}
+
+    # Compile
+    clang++ -std=c++17 -shared -fPIC \
+    -Wl,-no_compact_unwind -Wl,-framework,CoreFoundation \
+    -Wl,-framework,Security -Wl,-framework,VideoToolbox \
+    -Wl,-framework,CoreMedia -Wl,-framework,CoreVideo \
+    -Wl,-framework,OpenCl -Wl,-framework,Accelerate \
+    -Wl,-rpath,"\${ORIGIN}" \
+    -Wall -Wextra \
+    -Wno-unused-variable \
+    -Wno-unused-function \
+    -Wno-unused-parameter \
+    -I"." \
+    -I"${DAEMON_SRC}" \
+    -I"${CONTRIB_PATH}/${CONTRIB_PLATFORM}${CONTRIB_PLATFORM_EXTRA}/include" \
+    -I"${CONTRIB_PATH}/${CONTRIB_PLATFORM}${CONTRIB_PLATFORM_EXTRA}/include/opencv4" \
+    -I"${PLUGINS_LIB}" \
+    AudioHandlerTester.cpp \
+    AudioSubscriberTester.cpp \
+    VideoHandlerTester.cpp \
+    VideoSubscriberTester.cpp \
+    ChatHandlerTester.cpp \
+    ChatSubscriberTester.cpp \
+    main.cpp \
+    -L"${CONTRIB_PATH}/${CONTRIB_PLATFORM}${CONTRIB_PLATFORM_EXTRA}/lib/" \
+    -lavutil \
+    -lvpx -lx264 -lbz2 -liconv -lz -lspeex -lopus \
+    -o "build-local/jpl/lib/${CONTRIB_PLATFORM}/${SO_FILE_NAME}"
+
+    install_name_tool -id "@loader_path/${SO_FILE_NAME}" "build-local/jpl/lib/${CONTRIB_PLATFORM}/${SO_FILE_NAME}"
+
+    if [ -n "${APPLE_SIGN_CERTIFICATE}" ]; then
+      codesign --force --verify --timestamp -o runtime --sign "${APPLE_SIGN_CERTIFICATE}"  "build-local/jpl/lib/${CONTRIB_PLATFORM}/${SO_FILE_NAME}"
+      ditto -c -k --rsrc "build-local/jpl/lib/${CONTRIB_PLATFORM}/${SO_FILE_NAME}" "build-local/${SO_FILE_NAME}.zip"
+      LIBRARYNAME=${PLUGIN_NAME} sh ./../notarize.sh
+      cd ..
+      ditto -x -k "build-local/${SO_FILE_NAME}.zip" "build-local/notarized"
+      cp "build-local/notarized/${SO_FILE_NAME}" "build-local/jpl/lib/${CONTRIB_PLATFORM}/${SO_FILE_NAME}"
+    fi
+
+elif [ "${PLATFORM}" = "android" ]
+then
+    python3 ./../SDK/jplManipulation.py --preassemble --plugin=${PLUGIN_NAME} --distribution=${PLATFORM}
+
+    if [ -z "$ANDROID_NDK" ]; then
+            ANDROID_NDK="/home/${USER}/Android/Sdk/ndk/21.1.6352462"
+        echo "ANDROID_NDK not provided, building with ${ANDROID_NDK}"
+    fi
+
+    #=========================================================
+    #    Check if the ANDROID_ABI was provided
+    #    if not, set default
+    #=========================================================
+    if [ -z "$ANDROID_ABI" ]; then
+        ANDROID_ABI="armeabi-v7a arm64-v8a x86_64"
+        echo "ANDROID_ABI not provided, building for ${ANDROID_ABI}"
+    fi
+
+    buildlib() {
+        echo "$CURRENT_ABI"
+
+        #=========================================================
+        #    ANDROID TOOLS
+        #=========================================================
+        export HOST_TAG=linux-x86_64
+        export TOOLCHAIN=$ANDROID_NDK/toolchains/llvm/prebuilt/$HOST_TAG
+
+        if [ "$CURRENT_ABI" = armeabi-v7a ]
+        then
+        export AR=$TOOLCHAIN/bin/arm-linux-androideabi-ar
+        export AS=$TOOLCHAIN/bin/arm-linux-androideabi-as
+        export CC=$TOOLCHAIN/bin/armv7a-linux-androideabi21-clang
+        export CXX=$TOOLCHAIN/bin/armv7a-linux-androideabi21-clang++
+        export LD=$TOOLCHAIN/bin/arm-linux-androideabi-ld
+        export RANLIB=$TOOLCHAIN/bin/arm-linux-androideabi-ranlib
+        export STRIP=$TOOLCHAIN/bin/arm-linux-androideabi-strip
+        export ANDROID_SYSROOT=${DAEMON}/../client-android/android-toolchain-21-arm/sysroot
+
+        elif [ "$CURRENT_ABI" = arm64-v8a ]
+        then
+        export AR=$TOOLCHAIN/bin/aarch64-linux-android-ar
+        export AS=$TOOLCHAIN/bin/aarch64-linux-android-as
+        export CC=$TOOLCHAIN/bin/aarch64-linux-android21-clang
+        export CXX=$TOOLCHAIN/bin/aarch64-linux-android21-clang++
+        export LD=$TOOLCHAIN/bin/aarch64-linux-android-ld
+        export RANLIB=$TOOLCHAIN/bin/aarch64-linux-android-ranlib
+        export STRIP=$TOOLCHAIN/bin/aarch64-linux-android-strip
+        export ANDROID_SYSROOT=${DAEMON}/../client-android/android-toolchain-21-arm64/sysroot
+
+        elif [ "$CURRENT_ABI" = x86_64 ]
+        then
+        export AR=$TOOLCHAIN/bin/x86_64-linux-android-ar
+        export AS=$TOOLCHAIN/bin/x86_64-linux-android-as
+        export CC=$TOOLCHAIN/bin/x86_64-linux-android21-clang
+        export CXX=$TOOLCHAIN/bin/x86_64-linux-android21-clang++
+        export LD=$TOOLCHAIN/bin/x86_64-linux-android-ld
+        export RANLIB=$TOOLCHAIN/bin/x86_64-linux-android-ranlib
+        export STRIP=$TOOLCHAIN/bin/x86_64-linux-android-strip
+        export ANDROID_SYSROOT=${DAEMON}/../client-android/android-toolchain-21-x86_64/sysroot
+
+        else
+        echo "ABI NOT OK" >&2
+        exit 1
+        fi
+
+        #=========================================================
+        #    CONTRIBS
+        #=========================================================
+        if [ "$CURRENT_ABI" = armeabi-v7a ]
+        then
+        CONTRIB_PLATFORM=arm-linux-androideabi
+
+        elif [ "$CURRENT_ABI" = arm64-v8a ]
+        then
+        CONTRIB_PLATFORM=aarch64-linux-android
+
+        elif [ "$CURRENT_ABI" = x86_64 ]
+        then
+        CONTRIB_PLATFORM=x86_64-linux-android
+        fi
+
+        #NDK SOURCES FOR cpufeatures
+        NDK_SOURCES=${ANDROID_NDK}/sources/android
+
+        #=========================================================
+        #    LD_FLAGS
+        #=========================================================
+        if [ "$CURRENT_ABI" = armeabi-v7a ]
+        then
+        export EXTRA_LDFLAGS="${EXTRA_LDFLAGS} -L${ANDROID_SYSROOT}/usr/lib/arm-linux-androideabi -L${ANDROID_SYSROOT}/usr/lib/arm-linux-androideabi/21"
+        elif [ "$CURRENT_ABI" = arm64-v8a ]
+        then
+        export EXTRA_LDFLAGS="${EXTRA_LDFLAGS} -L${ANDROID_SYSROOT}/usr/lib/aarch64-linux-android -L${ANDROID_SYSROOT}/usr/lib/aarch64-linux-android/21"
+        elif [ "$CURRENT_ABI" = x86_64 ]
+        then
+        export EXTRA_LDFLAGS="${EXTRA_LDFLAGS} -L${ANDROID_SYSROOT}/usr/lib/x86_64-linux-android -L${ANDROID_SYSROOT}/usr/lib/x86_64-linux-android/21"
+        fi
+
+        #=========================================================
+        #    Compile the plugin
+        #=========================================================
+
+        # Create so destination folder
+        $CXX --std=c++17 -O3 -g -fPIC \
+        -Wl,-Bsymbolic,-rpath,"\${ORIGIN}" \
+        -shared \
+        -Wall -Wextra \
+        -Wno-unused-variable \
+        -Wno-unused-function \
+        -Wno-unused-parameter \
+        -I"." \
+        -I"${DAEMON_SRC}" \
+        -I"${CONTRIB_PATH}/${CONTRIB_PLATFORM}/include" \
+        -I"${CONTRIB_PATH}/${CONTRIB_PLATFORM}/include/opencv4" \
+        -I"${PLUGINS_LIB}" \
+        AudioHandlerTester.cpp \
+        AudioSubscriberTester.cpp \
+        VideoHandlerTester.cpp \
+        VideoSubscriberTester.cpp \
+        ChatHandlerTester.cpp \
+        ChatSubscriberTester.cpp \
+        main.cpp \
+        -L"${CONTRIB_PATH}/${CONTRIB_PLATFORM}/lib/" \
+        -lavutil \
+        -llog -lz \
+        --sysroot=$ANDROID_SYSROOT \
+        -o "build-local/jpl/lib/$CURRENT_ABI/${SO_FILE_NAME}"
+    }
+
+    # Build the so
+    for i in ${ANDROID_ABI}; do
+        CURRENT_ABI=$i
+        buildlib
+    done
+fi
+
+python3 ./../SDK/jplManipulation.py --assemble --plugin=${PLUGIN_NAME} --distribution=${PLATFORM} --extraPath=${EXTRAPATH}
diff --git a/TestSuite/data/accountpreferences.json b/TestSuite/data/accountpreferences.json
new file mode 100644
index 0000000..e1d4b8e
--- /dev/null
+++ b/TestSuite/data/accountpreferences.json
@@ -0,0 +1,9 @@
+[
+    {
+        "type": "EditText",
+        "key": "textAccountPreference",
+        "title": "{{text_translatable2}}",
+        "summary": "{{summary_translatable2}}",
+        "defaultValue": "{{default_translatable2}}"
+    }
+]
\ No newline at end of file
diff --git a/TestSuite/data/icon.png b/TestSuite/data/icon.png
new file mode 100644
index 0000000..437e408
--- /dev/null
+++ b/TestSuite/data/icon.png
Binary files differ
diff --git a/TestSuite/data/icon.svg b/TestSuite/data/icon.svg
new file mode 100644
index 0000000..4ced6a7
--- /dev/null
+++ b/TestSuite/data/icon.svg
@@ -0,0 +1,30 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<svg width="300px" height="300px" viewBox="0 0 300 300" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
+    <title>O</title>
+    <defs>
+        <linearGradient x1="50.001267%" y1="120.94311%" x2="50.001267%" y2="-257.222291%" id="linearGradient-1">
+            <stop stop-color="#EFB000" offset="0%"></stop>
+            <stop stop-color="#F1B904" offset="2.798313%"></stop>
+            <stop stop-color="#F6CF0E" offset="11.34%"></stop>
+            <stop stop-color="#FAE016" offset="21.42%"></stop>
+            <stop stop-color="#FDEB1B" offset="33.9%"></stop>
+            <stop stop-color="#FFF21E" offset="51.4%"></stop>
+            <stop stop-color="#FFF41F" offset="100%"></stop>
+        </linearGradient>
+        <linearGradient x1="49.9829639%" y1="-278.222509%" x2="49.9829639%" y2="99.9773676%" id="linearGradient-2">
+            <stop stop-color="#EFB000" offset="80.23%"></stop>
+            <stop stop-color="#F6CD0D" offset="85.32%"></stop>
+            <stop stop-color="#FBE317" offset="90.44%"></stop>
+            <stop stop-color="#FEF01D" offset="95.41%"></stop>
+            <stop stop-color="#FFF41F" offset="100%"></stop>
+        </linearGradient>
+    </defs>
+    <g id="Page-1" stroke="none" stroke-width="1" fill="none" fill-rule="evenodd">
+        <g id="O" fill-rule="nonzero">
+            <g transform="translate(2.000000, 0.000000)" id="Path">
+                <path d="M295.571429,152.285714 C295.571429,152.214286 295.571429,152.142857 295.571429,152.071429 C295.571429,150.428571 295.571429,148.714286 295.5,146.928571 C295.5,146.214286 295.5,145.428571 295.5,144.714286 L295.428571,144.714286 C293.857143,105.928571 280.071429,50.7142857 210.642857,15.1428571 C135.928571,-23.0714286 70.0714286,23.3571429 70.0714286,23.3571429 C70.1428571,23.3571429 70.1428571,23.3571429 70.2142857,23.3571429 C110.857143,16.2857143 172.357143,46.8571429 206.285714,90.9285714 C211.571429,97.7857143 216.214286,104.928571 219.928571,112.357143 C226.214286,124.642857 228.928571,136.214286 229.428571,146.642857 C229.428571,147.071429 229.5,147.571429 229.5,148 C229.571429,151.357143 229.5,154.714286 229.142857,157.857143 L229.142857,157.857143 C227.357143,176.214286 219,194.071429 205,208.142857 C173.428571,239.642857 121.142857,240.142857 89.5714286,208.571429 L89.4285714,209.142857 C123.357143,253.214286 184.857143,283.785714 225.5,276.714286 C235.071429,270.785714 244.071429,263.785714 252.357143,255.5 C279.428571,228.428571 293.714286,193.428571 295.357143,157.928571 L295.5,157.928571 C295.571429,156.428571 295.571429,154.928571 295.571429,153.428571 C295.571429,153 295.571429,152.642857 295.571429,152.285714 Z" fill="url(#linearGradient-1)"></path>
+                <path d="M225.5,276.642857 C184.857143,283.714286 123.357143,253.142857 89.4285714,209.071429 C84.1428571,202.214286 79.5,195.071429 75.7857143,187.642857 C69.5,175.357143 66.7857143,163.785714 66.2857143,153.357143 C66.2857143,152.928571 66.2142857,152.428571 66.2142857,152 C66.1428571,148.642857 66.2142857,145.285714 66.5714286,142.142857 L66.5714286,142.142857 C68.3571429,123.785714 76.7142857,105.928571 90.7142857,91.8571429 C122.285714,60.3571429 174.571429,59.8571429 206.142857,91.4285714 L206.285714,90.8571429 C172.357143,46.8571429 110.857143,16.2857143 70.2142857,23.3571429 C60.6428571,29.2857143 51.6428571,36.2857143 43.3571429,44.5714286 C16.2857143,71.6428571 2,106.642857 0.357142857,142.142857 L0.214285714,142.142857 C0.142857143,143.642857 0.142857143,145.142857 0.142857143,146.642857 C0.142857143,147 0.142857143,147.357143 0.142857143,147.714286 C0.142857143,147.785714 0.142857143,147.857143 0.142857143,147.928571 C0.142857143,149.571429 0.142857143,151.285714 0.214285714,153.071429 C0.214285714,153.785714 0.214285714,154.571429 0.285714286,155.285714 L0.357142857,155.285714 C1.92857143,194.071429 15.7142857,249.285714 85.1428571,284.857143 C159.857143,323.142857 225.714286,276.714286 225.714286,276.714286 C225.571429,276.642857 225.571429,276.642857 225.5,276.642857 Z" fill="url(#linearGradient-2)"></path>
+            </g>
+        </g>
+    </g>
+</svg>
\ No newline at end of file
diff --git a/TestSuite/data/locale/TestSuite_en.json b/TestSuite/data/locale/TestSuite_en.json
new file mode 100644
index 0000000..866f977
--- /dev/null
+++ b/TestSuite/data/locale/TestSuite_en.json
@@ -0,0 +1,8 @@
+{
+    "text_translatable1": "text one in english",
+    "text_translatable2": "text two in english",
+    "summary_translatable1": "summary one in english",
+    "summary_translatable2": "summary two in english",
+    "default_translatable1": "default one in english",
+    "default_translatable2": "default two in english"
+}
diff --git a/TestSuite/data/locale/TestSuite_fr.json b/TestSuite/data/locale/TestSuite_fr.json
new file mode 100644
index 0000000..c292bca
--- /dev/null
+++ b/TestSuite/data/locale/TestSuite_fr.json
@@ -0,0 +1,8 @@
+{
+    "text_translatable1": "text un en français",
+    "text_translatable2": "text deux en français",
+    "summary_translatable1": "summary un en français",
+    "summary_translatable2": "summary deux en français",
+    "default_translatable1": "default un en français",
+    "default_translatable2": "default deux en français"
+}
diff --git a/TestSuite/data/preferences.json b/TestSuite/data/preferences.json
new file mode 100644
index 0000000..d6a496d
--- /dev/null
+++ b/TestSuite/data/preferences.json
@@ -0,0 +1,9 @@
+[
+    {
+        "type": "EditText",
+        "key": "textGlobalPreference",
+        "title": "{{text_translatable1}}",
+        "summary": "{{summary_translatable1}}",
+        "defaultValue": "{{default_translatable1}}"
+    }
+]
\ No newline at end of file
diff --git a/TestSuite/main.cpp b/TestSuite/main.cpp
new file mode 100644
index 0000000..cca526c
--- /dev/null
+++ b/TestSuite/main.cpp
@@ -0,0 +1,86 @@
+/**
+ *  Copyright (C) 2020-2021 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, write to the Free Software
+ *  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301 USA.
+ */
+
+#include <iostream>
+#include <string.h>
+#include <thread>
+#include <memory>
+#include <plugin/jamiplugin.h>
+
+#include "AudioHandlerTester.h"
+#include "VideoHandlerTester.h"
+#include "ChatHandlerTester.h"
+
+#ifdef WIN32
+#define EXPORT_PLUGIN __declspec(dllexport)
+#else
+#define EXPORT_PLUGIN
+#endif
+
+#define TestSuite_VERSION_MAJOR 1
+#define TestSuite_VERSION_MINOR 0
+#define TestSuite_VERSION_PATCH 0
+
+extern "C" {
+void
+pluginExit(void)
+{}
+
+EXPORT_PLUGIN JAMI_PluginExitFunc
+JAMI_dynPluginInit(const JAMI_PluginAPI* api)
+{
+    std::cout << "*******************" << std::endl;
+    std::cout << "**   TestSuite   **" << std::endl;
+    std::cout << "*******************" << std::endl << std::endl;
+    std::cout << "Version " << TestSuite_VERSION_MAJOR << "." << TestSuite_VERSION_MINOR << "."
+              << TestSuite_VERSION_PATCH << std::endl;
+
+    // If invokeService doesn't return an error
+    if (api) {
+        std::string dataPath;
+        api->invokeService(api, "getPluginDataPath", &dataPath);
+
+        auto fmpAudio
+            = std::make_unique<jami::AudioHandlerTester>(std::move(dataPath));
+        if (api->manageComponent(api,
+                                 "CallMediaHandlerManager",
+                                 fmpAudio.release())) {
+            return nullptr;
+        }
+
+        auto fmpVideo
+            = std::make_unique<jami::VideoHandlerTester>(std::move(dataPath));
+        if (api->manageComponent(api,
+                                 "CallMediaHandlerManager",
+                                 fmpVideo.release())) {
+            return nullptr;
+        }
+
+        auto fmpChat
+            = std::make_unique<jami::ChatHandlerTester>(std::move(dataPath));
+        if (api->manageComponent(api,
+                                 "ChatHandlerManager",
+                                 fmpChat.release())) {
+            return nullptr;
+        }
+    }
+    return pluginExit;
+}
+}
diff --git a/TestSuite/manifest.json b/TestSuite/manifest.json
new file mode 100644
index 0000000..5ff8a07
--- /dev/null
+++ b/TestSuite/manifest.json
@@ -0,0 +1,6 @@
+{
+    "name": "TestSuite",
+    "description": "TestSuite is a empty process plugin conceived for use in the daemon unit tests.",
+    "version": "1.0.0",
+    "iconPath" : "icon.svg"
+}
\ No newline at end of file
diff --git a/TestSuite/package.json b/TestSuite/package.json
new file mode 100644
index 0000000..f4ad235
--- /dev/null
+++ b/TestSuite/package.json
@@ -0,0 +1,19 @@
+{
+    "name": "TestSuite",
+    "version": "1.0.0",
+    "extractLibs": false,
+    "deps": [
+        "fmt",
+        "ffmpeg"
+    ],
+    "defines": [],
+    "custom_scripts": {
+        "pre_build": [
+            "mkdir msvc"
+        ],
+        "build": [
+            "cmake --build ./msvc --config Release"
+        ],
+        "post_build": []
+    }
+}
\ No newline at end of file