Even more unit tests.

This commit is contained in:
Gunnar Beutner 2013-04-19 12:58:16 +02:00
parent d0113e33da
commit fcdb690b48
6 changed files with 149 additions and 24 deletions

View File

@ -271,8 +271,7 @@ Dictionary::Ptr Dictionary::FromJson(cJSON *json)
{ {
Dictionary::Ptr dictionary = boost::make_shared<Dictionary>(); Dictionary::Ptr dictionary = boost::make_shared<Dictionary>();
if (json->type != cJSON_Object) ASSERT(json->type == cJSON_Object);
BOOST_THROW_EXCEPTION(std::invalid_argument("JSON type must be cJSON_Object."));
for (cJSON *i = json->child; i != NULL; i = i->next) { for (cJSON *i = json->child; i != NULL; i = i->next) {
dictionary->Set(i->string, Value::FromJson(i)); dictionary->Set(i->string, Value::FromJson(i));

View File

@ -26,20 +26,19 @@
#include <boost/bind.hpp> #include <boost/bind.hpp>
#include <boost/exception/diagnostic_information.hpp> #include <boost/exception/diagnostic_information.hpp>
#include <boost/foreach.hpp> #include <boost/foreach.hpp>
#include <boost/chrono/duration.hpp>
using namespace icinga; using namespace icinga;
ThreadPool::ThreadPool(void) 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++) for (int i = 0; i < 2; i++)
SpawnWorker(); SpawnWorker();
boost::thread managerThread(boost::bind(&ThreadPool::ManagerThreadProc, this)); m_ManagerThread = boost::thread(boost::bind(&ThreadPool::ManagerThreadProc, this));
managerThread.detach(); m_StatsThread = boost::thread(boost::bind(&ThreadPool::StatsThreadProc, this));
boost::thread statsThread(boost::bind(&ThreadPool::StatsThreadProc, this));
statsThread.detach();
} }
ThreadPool::~ThreadPool(void) ThreadPool::~ThreadPool(void)
@ -52,7 +51,8 @@ void ThreadPool::Stop(void)
{ {
boost::mutex::scoped_lock lock(m_Mutex); boost::mutex::scoped_lock lock(m_Mutex);
m_Stopped = true; 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); Utility::Sleep(0.5);
lock.lock(); 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); UpdateThreadUtilization(tid, ThreadIdle);
while (m_WorkItems.empty() && !m_Stopped && m_ThreadDeaths == 0) while (m_WorkItems.empty() && !m_Stopped && m_ThreadDeaths == 0)
m_CV.wait(lock); m_WorkCV.wait(lock);
if (m_ThreadDeaths > 0) { if (m_ThreadDeaths > 0) {
m_ThreadDeaths--; m_ThreadDeaths--;
@ -190,7 +211,7 @@ void ThreadPool::Post(const ThreadPool::WorkFunction& callback)
wi.Timestamp = Utility::GetTime(); wi.Timestamp = Utility::GetTime();
m_WorkItems.push_back(wi); m_WorkItems.push_back(wi);
m_CV.notify_one(); m_WorkCV.notify_one();
} }
void ThreadPool::ManagerThreadProc(void) void ThreadPool::ManagerThreadProc(void)
@ -200,16 +221,18 @@ void ThreadPool::ManagerThreadProc(void)
Utility::SetThreadName(idbuf.str()); Utility::SetThreadName(idbuf.str());
for (;;) { for (;;) {
Utility::Sleep(5);
double now = Utility::GetTime();
int pending, alive; int pending, alive;
double avg_latency, max_latency; double avg_latency, max_latency;
double utilization = 0; double utilization = 0;
{ {
boost::mutex::scoped_lock lock(m_Mutex); 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(); pending = m_WorkItems.size();
alive = 0; alive = 0;
@ -299,16 +322,17 @@ void ThreadPool::StatsThreadProc(void)
Utility::SetThreadName(idbuf.str()); Utility::SetThreadName(idbuf.str());
for (;;) { 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));
if (m_Stopped)
break;
for (int i = 0; i < sizeof(m_ThreadStats) / sizeof(m_ThreadStats[0]); i++) for (int i = 0; i < sizeof(m_ThreadStats) / sizeof(m_ThreadStats[0]); i++)
UpdateThreadUtilization(i); UpdateThreadUtilization(i);
} }
} }
}
/** /**
* Note: Caller must hold m_Mutex. * Note: Caller must hold m_Mutex.

View File

@ -71,6 +71,9 @@ private:
ThreadStats m_ThreadStats[512]; ThreadStats m_ThreadStats[512];
int m_ThreadDeaths; int m_ThreadDeaths;
boost::thread m_ManagerThread;
boost::thread m_StatsThread;
double m_WaitTime; double m_WaitTime;
double m_ServiceTime; double m_ServiceTime;
int m_TaskCount; int m_TaskCount;
@ -78,7 +81,8 @@ private:
double m_MaxLatency; double m_MaxLatency;
boost::mutex m_Mutex; boost::mutex m_Mutex;
boost::condition_variable m_CV; boost::condition_variable m_WorkCV;
boost::condition_variable m_MgmtCV;
bool m_Stopped; bool m_Stopped;

View File

@ -20,6 +20,7 @@
#include "base/timer.h" #include "base/timer.h"
#include "base/application.h" #include "base/application.h"
#include "base/utility.h" #include "base/utility.h"
#include "base/logger_fwd.h"
#include <boost/bind.hpp> #include <boost/bind.hpp>
#include <boost/thread/thread.hpp> #include <boost/thread/thread.hpp>
#include <boost/thread/mutex.hpp> #include <boost/thread/mutex.hpp>
@ -300,6 +301,6 @@ void Timer::TimerThreadProc(void)
lock.unlock(); lock.unlock();
/* Asynchronously call the timer. */ /* Asynchronously call the timer. */
Application::GetTP().Post(boost::bind(&Timer::Call, timer)); Utility::QueueAsyncCallback(boost::bind(&Timer::Call, timer));
} }
} }

View File

@ -13,7 +13,8 @@ icinga2_test_SOURCES = \
base-dictionary.cpp \ base-dictionary.cpp \
base-fifo.cpp \ base-fifo.cpp \
base-object.cpp \ base-object.cpp \
base-shellescape.cpp base-shellescape.cpp \
base-timer.cpp
icinga2_test_CPPFLAGS = \ icinga2_test_CPPFLAGS = \
$(BOOST_CPPFLAGS) \ $(BOOST_CPPFLAGS) \

96
test/base-timer.cpp Normal file
View File

@ -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()