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

View File

@ -26,20 +26,19 @@
#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);
}
}

View 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;

View 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));
}
}

View 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) \

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