]> granicus.if.org Git - icinga2/commitdiff
Even more unit tests.
authorGunnar Beutner <gunnar.beutner@netways.de>
Fri, 19 Apr 2013 10:58:16 +0000 (12:58 +0200)
committerGunnar Beutner <gunnar.beutner@netways.de>
Fri, 19 Apr 2013 10:58:16 +0000 (12:58 +0200)
lib/base/dictionary.cpp
lib/base/threadpool.cpp
lib/base/threadpool.h
lib/base/timer.cpp
test/Makefile.am
test/base-timer.cpp [new file with mode: 0644]

index eb72fd6c87a2990358039833cbdb8f4945e497ec..c63110ab1ad468b0d8babc4d9e75af5cf659a298 100644 (file)
@@ -271,8 +271,7 @@ Dictionary::Ptr Dictionary::FromJson(cJSON *json)
 {
        Dictionary::Ptr dictionary = boost::make_shared<Dictionary>();
 
-       if (json->type != cJSON_Object)
-               BOOST_THROW_EXCEPTION(std::invalid_argument("JSON type must be cJSON_Object."));
+       ASSERT(json->type == cJSON_Object);
 
        for (cJSON *i = json->child; i != NULL; i = i->next) {
                dictionary->Set(i->string, Value::FromJson(i));
index 6627906da91d441f69c96c613647429473e61567..e110f0b29c0d885f38b8cdb4274397a0d802e45b 100644 (file)
 #include <boost/bind.hpp>
 #include <boost/exception/diagnostic_information.hpp>
 #include <boost/foreach.hpp>
+#include <boost/chrono/duration.hpp>
 
 using namespace icinga;
 
 ThreadPool::ThreadPool(void)
-       : m_Stopped(false), m_ThreadDeaths(0), m_WaitTime(0), m_ServiceTime(0), m_TaskCount(0)
+       : m_Stopped(false), m_ThreadDeaths(0), m_WaitTime(0),
+         m_ServiceTime(0), m_TaskCount(0)
 {
        for (int i = 0; i < 2; i++)
                SpawnWorker();
 
-       boost::thread managerThread(boost::bind(&ThreadPool::ManagerThreadProc, this));
-       managerThread.detach();
-
-       boost::thread statsThread(boost::bind(&ThreadPool::StatsThreadProc, this));
-       statsThread.detach();
+       m_ManagerThread = boost::thread(boost::bind(&ThreadPool::ManagerThreadProc, this));
+       m_StatsThread = boost::thread(boost::bind(&ThreadPool::StatsThreadProc, this));
 }
 
 ThreadPool::~ThreadPool(void)
@@ -52,7 +51,8 @@ void ThreadPool::Stop(void)
 {
        boost::mutex::scoped_lock lock(m_Mutex);
        m_Stopped = true;
-       m_CV.notify_all();
+       m_WorkCV.notify_all();
+       m_MgmtCV.notify_all();
 }
 
 /**
@@ -67,6 +67,27 @@ void ThreadPool::Join(void)
                Utility::Sleep(0.5);
                lock.lock();
        }
+
+       int alive;
+
+       do {
+               alive = 0;
+               for (int i = 0; i < sizeof(m_ThreadStats) / sizeof(m_ThreadStats[0]); i++) {
+                       if (m_ThreadStats[i].State != ThreadDead) {
+                               alive++;
+                               KillWorker();
+                       }
+               }
+
+               if (alive > 0) {
+                       lock.unlock();
+                       Utility::Sleep(0.5);
+                       lock.lock();
+               }
+       } while (alive > 0);
+
+       m_ManagerThread.join();
+       m_StatsThread.join();
 }
 
 /**
@@ -87,7 +108,7 @@ void ThreadPool::QueueThreadProc(int tid)
                        UpdateThreadUtilization(tid, ThreadIdle);
 
                        while (m_WorkItems.empty() && !m_Stopped && m_ThreadDeaths == 0)
-                               m_CV.wait(lock);
+                               m_WorkCV.wait(lock);
 
                        if (m_ThreadDeaths > 0) {
                                m_ThreadDeaths--;
@@ -190,7 +211,7 @@ void ThreadPool::Post(const ThreadPool::WorkFunction& callback)
        wi.Timestamp = Utility::GetTime();
 
        m_WorkItems.push_back(wi);
-       m_CV.notify_one();
+       m_WorkCV.notify_one();
 }
 
 void ThreadPool::ManagerThreadProc(void)
@@ -200,16 +221,18 @@ void ThreadPool::ManagerThreadProc(void)
        Utility::SetThreadName(idbuf.str());
 
        for (;;) {
-               Utility::Sleep(5);
-
-               double now = Utility::GetTime();
-
                int pending, alive;
                double avg_latency, max_latency;
                double utilization = 0;
 
                {
                        boost::mutex::scoped_lock lock(m_Mutex);
+
+                       m_MgmtCV.timed_wait(lock, boost::posix_time::seconds(5));
+
+                       if (m_Stopped)
+                               break;
+
                        pending = m_WorkItems.size();
 
                        alive = 0;
@@ -299,14 +322,15 @@ void ThreadPool::StatsThreadProc(void)
        Utility::SetThreadName(idbuf.str());
 
        for (;;) {
-               Utility::Sleep(0.25);
+               boost::mutex::scoped_lock lock(m_Mutex);
 
-               {
-                       boost::mutex::scoped_lock lock(m_Mutex);
+               m_MgmtCV.timed_wait(lock, boost::posix_time::milliseconds(250));
 
-                       for (int i = 0; i < sizeof(m_ThreadStats) / sizeof(m_ThreadStats[0]); i++)
-                               UpdateThreadUtilization(i);
-               }
+               if (m_Stopped)
+                       break;
+
+               for (int i = 0; i < sizeof(m_ThreadStats) / sizeof(m_ThreadStats[0]); i++)
+                       UpdateThreadUtilization(i);
        }
 }
 
index 4edbce3d3d7bb0e08caf91265985f5da2cab8fcd..7bb16aa2c37bec237d6265ebbaefd77cfb8a6c6f 100644 (file)
@@ -71,6 +71,9 @@ private:
        ThreadStats m_ThreadStats[512];
        int m_ThreadDeaths;
 
+       boost::thread m_ManagerThread;
+       boost::thread m_StatsThread;
+
        double m_WaitTime;
        double m_ServiceTime;
        int m_TaskCount;
@@ -78,7 +81,8 @@ private:
        double m_MaxLatency;
 
        boost::mutex m_Mutex;
-       boost::condition_variable m_CV;
+       boost::condition_variable m_WorkCV;
+       boost::condition_variable m_MgmtCV;
 
        bool m_Stopped;
 
index 57cd34ed3ba8ba80e0399061fbaa455f19984d16..4f644a030d53038f412e2a9712ff42c4f9c226ad 100644 (file)
@@ -20,6 +20,7 @@
 #include "base/timer.h"
 #include "base/application.h"
 #include "base/utility.h"
+#include "base/logger_fwd.h"
 #include <boost/bind.hpp>
 #include <boost/thread/thread.hpp>
 #include <boost/thread/mutex.hpp>
@@ -300,6 +301,6 @@ void Timer::TimerThreadProc(void)
                lock.unlock();
 
                /* Asynchronously call the timer. */
-               Application::GetTP().Post(boost::bind(&Timer::Call, timer));
+               Utility::QueueAsyncCallback(boost::bind(&Timer::Call, timer));
        }
 }
index 6a146296fa40e0cc87ae0721d2a14bcf639a5ba7..3199fca59d5264dc96c245f6627eac77661d62a2 100644 (file)
@@ -13,7 +13,8 @@ icinga2_test_SOURCES = \
        base-dictionary.cpp \
        base-fifo.cpp \
        base-object.cpp \
-       base-shellescape.cpp
+       base-shellescape.cpp \
+       base-timer.cpp
 
 icinga2_test_CPPFLAGS = \
        $(BOOST_CPPFLAGS) \
diff --git a/test/base-timer.cpp b/test/base-timer.cpp
new file mode 100644 (file)
index 0000000..b7431e3
--- /dev/null
@@ -0,0 +1,96 @@
+/******************************************************************************
+ * Icinga 2                                                                   *
+ * Copyright (C) 2012 Icinga Development Team (http://www.icinga.org/)        *
+ *                                                                            *
+ * 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 2             *
+ * 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 St, Fifth Floor, Boston, MA 02110-1301, USA.             *
+ ******************************************************************************/
+
+#include "base/timer.h"
+#include "base/utility.h"
+#include "base/application.h"
+#include <boost/test/unit_test.hpp>
+#include <boost/smart_ptr/make_shared.hpp>
+#include <boost/foreach.hpp>
+#include <iostream>
+
+using namespace icinga;
+
+struct TimerFixture
+{
+       TimerFixture(void)
+       {
+               Timer::Initialize();
+       }
+
+       ~TimerFixture(void)
+       {
+               Timer::Uninitialize();
+       }
+};
+
+BOOST_FIXTURE_TEST_SUITE(base_timer, TimerFixture)
+
+BOOST_AUTO_TEST_CASE(construct)
+{
+       Timer::Ptr timer = boost::make_shared<Timer>();
+       BOOST_CHECK(timer);
+}
+
+BOOST_AUTO_TEST_CASE(interval)
+{
+       Timer::Ptr timer = boost::make_shared<Timer>();
+       timer->SetInterval(1.5);
+       BOOST_CHECK(timer->GetInterval() == 1.5);
+}
+
+static void Callback(int *counter)
+{
+       (*counter)++;
+}
+
+BOOST_AUTO_TEST_CASE(invoke)
+{
+       int counter;
+       Timer::Ptr timer = boost::make_shared<Timer>();
+       timer->OnTimerExpired.connect(boost::bind(&Callback, &counter));
+       timer->SetInterval(1);
+
+       counter = 0;
+       timer->Start();
+       Utility::Sleep(5.5);
+       timer->Stop();
+
+       std::cout << counter << std::endl;
+       BOOST_CHECK(counter >= 4 && counter <= 6);
+}
+
+BOOST_AUTO_TEST_CASE(scope)
+{
+       int counter;
+       Timer::Ptr timer = boost::make_shared<Timer>();
+       timer->OnTimerExpired.connect(boost::bind(&Callback, &counter));
+       timer->SetInterval(1);
+
+       counter = 0;
+       timer->Start();
+       Utility::Sleep(5.5);
+       timer.reset();
+       Utility::Sleep(5.5);
+
+       std::cout << counter << std::endl;
+       BOOST_CHECK(counter >= 4 && counter <= 6);
+}
+
+BOOST_AUTO_TEST_SUITE_END()