diff --git a/src/scheduled_executor.cpp b/src/scheduled_executor.cpp
index 6119f2ed129c061ae2660eb23de5355f8ba9e944..2d98f6b0d687cfa260fd4abc89c30dd9a0f6779e 100644
--- a/src/scheduled_executor.cpp
+++ b/src/scheduled_executor.cpp
@@ -109,8 +109,10 @@ ScheduledExecutor::loop()
         while (running_ and (jobs_.empty() or jobs_.begin()->first > clock::now())) {
             if (jobs_.empty())
                 cv_.wait(lock);
-            else
-                cv_.wait_until(lock, jobs_.begin()->first);
+            else {
+                auto nextJob = jobs_.begin()->first;
+                cv_.wait_until(lock, nextJob);
+            }
         }
         if (not running_)
             return;
diff --git a/test/unitTest/Makefile.am b/test/unitTest/Makefile.am
index 4747e2e5645eb9b67824f2053abeb950209de7fe..495fb4a685b2cdae5a3bec37f13bda28ceb1dad2 100644
--- a/test/unitTest/Makefile.am
+++ b/test/unitTest/Makefile.am
@@ -20,6 +20,13 @@ check_PROGRAMS += ut_certstore
 ut_certstore_SOURCES = certstore.cpp
 ut_certstore_LDADD = @OPENDHT_LIBS@
 
+#
+# scheduler
+#
+check_PROGRAMS += ut_scheduler
+ut_scheduler_SOURCES = scheduler.cpp
+ut_scheduler_LDADD = @OPENDHT_LIBS@
+
 #
 # base64
 #
diff --git a/test/unitTest/scheduler.cpp b/test/unitTest/scheduler.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..125403c86aca97dbacafa4cd7f84ae963a2d3d2b
--- /dev/null
+++ b/test/unitTest/scheduler.cpp
@@ -0,0 +1,92 @@
+/*
+ *  Copyright (C) 2004-2020 Savoir-faire Linux Inc.
+ *
+ *  Author: Adrien Béraud <adrien.beraud@savoirfaielinux.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 <cppunit/TestAssert.h>
+#include <cppunit/TestFixture.h>
+#include <cppunit/extensions/HelperMacros.h>
+
+#include "test_runner.h"
+
+#include "scheduled_executor.h"
+#include <opendht/rng.h>
+
+namespace jami { namespace test {
+
+class SchedulerTest : public CppUnit::TestFixture {
+public:
+    static std::string name() { return "scheduler"; }
+
+private:
+    void schedulerTest();
+
+    CPPUNIT_TEST_SUITE(SchedulerTest);
+    CPPUNIT_TEST(schedulerTest);
+    CPPUNIT_TEST_SUITE_END();
+};
+
+CPPUNIT_TEST_SUITE_NAMED_REGISTRATION(SchedulerTest, SchedulerTest::name());
+
+void
+SchedulerTest::schedulerTest()
+{
+    jami::ScheduledExecutor executor;
+
+    constexpr unsigned N = 1024;
+    std::mutex mtx;
+    std::condition_variable cv;
+    std::unique_lock<std::mutex> lk(mtx);
+
+    std::atomic_uint64_t taskRun {0};
+    std::atomic_uint64_t result {0};
+
+    auto task = [&]{
+        auto rng = dht::crypto::getSeededRandomEngine();
+        uint64_t sum {0};
+        for (uint64_t i=0; i<64 * N; i++)
+            sum += rng();
+        result += sum;
+        std::lock_guard<std::mutex> l(mtx);
+        if (++taskRun == N)
+            cv.notify_all();
+    };
+    CPPUNIT_ASSERT(taskRun == 0);
+
+    for (unsigned i=0; i<N; i++)
+        executor.run(task);
+
+    CPPUNIT_ASSERT(cv.wait_for(lk, std::chrono::seconds(2), [&]{
+        return taskRun == N;
+    }));
+
+    for (unsigned i=0; i<N; i++)
+        executor.scheduleIn(task, std::chrono::microseconds(1));
+
+    CPPUNIT_ASSERT(cv.wait_for(lk, std::chrono::seconds(2), [&]{
+        return taskRun == 2 * N;
+    }));
+
+    for (unsigned i=0; i<N; i++)
+        executor.scheduleIn(task, std::chrono::microseconds(1));
+    executor.stop();
+}
+
+}} // namespace jami::test
+
+RING_TEST_RUNNER(jami::test::SchedulerTest::name());