diff --git a/test/unitTest/Makefile.am b/test/unitTest/Makefile.am
index a5acff7bb101f3d88f4d028829c192831473b49a..579f29ff8546477f58512c946ff03cf5b1768828 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 0000000000000000000000000000000000000000..6b86b98d3b260ad9d1faeb75cdf959d8723e7f4c
--- /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 e6a4a02156ea03137c9bc53258c9b115859d40ad..39bfba91bafb2c374465ccdb561b005b7b6a3554 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"