From 3ce9904160d003031a07ccde512306b7cee47f25 Mon Sep 17 00:00:00 2001 From: sbund <sbund@wiback.org> Date: Wed, 12 Jul 2006 09:55:22 +0000 Subject: [PATCH] Added unit-tests --- SConstruct | 1 - Scheduler/Scheduler.cc | 68 +++++++++++--- Scheduler/Scheduler.cci | 44 +++++++++ Scheduler/Scheduler.hh | 16 +++- Scheduler/Scheduler.test.cc | 180 ++++++++++++++++++++++++++++++++++++ 5 files changed, 291 insertions(+), 18 deletions(-) create mode 100644 Scheduler/Scheduler.cci diff --git a/SConstruct b/SConstruct index 4b95deca4..8e520fda8 100644 --- a/SConstruct +++ b/SConstruct @@ -22,4 +22,3 @@ Export('env satscons') SConscript(glob.glob("*/SConscript")) SatSCons.StandardTargets(env) -SatSCons.AllTests(env) diff --git a/Scheduler/Scheduler.cc b/Scheduler/Scheduler.cc index 71cfb3b98..6ea88cc1b 100644 --- a/Scheduler/Scheduler.cc +++ b/Scheduler/Scheduler.cc @@ -48,7 +48,7 @@ prefix_ satcom::lib::Scheduler::Scheduler() throw SystemException(errno); } -prefix_ void satcom::lib::Scheduler::set(int fd, Callback const & cb, EventId eventMask) +prefix_ void satcom::lib::Scheduler::add(int fd, Callback const & cb, EventId eventMask) { FdTable::iterator i (fdTable_.find(fd)); int action (EPOLL_CTL_MOD); @@ -57,34 +57,38 @@ prefix_ void satcom::lib::Scheduler::set(int fd, Callback const & cb, EventId ev i = fdTable_.insert(std::make_pair(fd, EventSpec())).first; } - if (eventMask | EV_READ) i->second.cb_read = cb; - if (eventMask | EV_WRITE) i->second.cb_write = cb; - if (eventMask | EV_HUP) i->second.cb_hup = cb; - if (eventMask | EV_ERR) i->second.cb_err = cb; + if (eventMask & EV_READ) i->second.cb_read = cb; + if (eventMask & EV_PRIO) i->second.cb_prio = cb; + if (eventMask & EV_WRITE) i->second.cb_write = cb; + if (eventMask & EV_HUP) i->second.cb_hup = cb; + if (eventMask & EV_ERR) i->second.cb_err = cb; epoll_event ev; memset(&ev,0,sizeof(ev)); ev.events = i->second.epollMask(); + ev.data.fd = fd; if (epoll_ctl(epollFd_, action, fd, &ev)<0) throw SystemException(errno); } -prefix_ void satcom::lib::Scheduler::unset(int fd, EventId eventMask) +prefix_ void satcom::lib::Scheduler::remove(int fd, EventId eventMask) { FdTable::iterator i (fdTable_.find(fd)); if (i == fdTable_.end()) return; - if (eventMask | EV_READ) i->second.cb_read = 0; - if (eventMask | EV_WRITE) i->second.cb_write = 0; - if (eventMask | EV_HUP) i->second.cb_hup = 0; - if (eventMask | EV_ERR) i->second.cb_err = 0; + if (eventMask & EV_READ) i->second.cb_read = 0; + if (eventMask & EV_PRIO) i->second.cb_prio = 0; + if (eventMask & EV_WRITE) i->second.cb_write = 0; + if (eventMask & EV_HUP) i->second.cb_hup = 0; + if (eventMask & EV_ERR) i->second.cb_err = 0; epoll_event ev; memset(&ev,0,sizeof(ev)); ev.events = i->second.epollMask(); - + ev.data.fd = fd; + int action (EPOLL_CTL_MOD); if (ev.events==0) { action = EPOLL_CTL_DEL; @@ -99,13 +103,53 @@ prefix_ int satcom::lib::Scheduler::EventSpec::epollMask() const { int mask (0); - if (cb_read) mask |= EPOLLIN | EPOLLPRI; + if (cb_read) mask |= EPOLLIN; + if (cb_prio) mask |= EPOLLPRI; if (cb_write) mask |= EPOLLOUT; if (cb_hup) mask |= EPOLLHUP; if (cb_err) mask |= EPOLLERR; return mask; } +prefix_ void satcom::lib::Scheduler::process() +{ + terminate_ = false; + while (! terminate_) { + struct epoll_event ev; + int events = epoll_wait(epollFd_, &ev, 1, 1000); + if (events<0) + throw SystemException(errno); + if (events==0) + continue; + + FdTable::iterator i = fdTable_.find(ev.data.fd); + BOOST_ASSERT (i != fdTable_.end() ); + EventSpec const & spec (i->second); + + if (ev.events & EPOLLIN) { + BOOST_ASSERT(spec.cb_read); + spec.cb_read(ev.data.fd, EV_READ); + } + else if (ev.events & EPOLLPRI) { + BOOST_ASSERT(spec.cb_prio); + spec.cb_prio (ev.data.fd, EV_PRIO); + } + else if (ev.events & EPOLLOUT) { + BOOST_ASSERT(spec.cb_write); + spec.cb_write(ev.data.fd, EV_WRITE); + } + + else if (ev.events & EPOLLHUP) { + BOOST_ASSERT(spec.cb_hup); + spec.cb_hup(ev.data.fd, EV_HUP); + } + else if (ev.events & EPOLLERR) { + BOOST_ASSERT(spec.cb_err); + spec.cb_err(ev.data.fd, EV_ERR); + } + } +} + ///////////////////////////////cc.e//////////////////////////////////////// #undef prefix_ diff --git a/Scheduler/Scheduler.cci b/Scheduler/Scheduler.cci new file mode 100644 index 000000000..f34286e48 --- /dev/null +++ b/Scheduler/Scheduler.cci @@ -0,0 +1,44 @@ +// $Id$ +// +// Copyright (C) 2006 +// Fraunhofer Institut fuer offene Kommunikationssysteme (FOKUS) +// Kompetenzzentrum fuer Satelitenkommunikation (SatCom) +// Stefan Bund <stefan.bund@fokus.fraunhofer.de> +// +// 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., +// 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + +// Definition of inline non-template functions + +//#include "Scheduler.ih" + +// Custom includes + +#define prefix_ inline +///////////////////////////////cci.p/////////////////////////////////////// + +prefix_ void satcom::lib::Scheduler::terminate() +{ + terminate_ = true; +} + +///////////////////////////////cci.e/////////////////////////////////////// +#undef prefix_ + + +// Local Variables: +// mode: c++ +// c-file-style: "satcom" +// End: diff --git a/Scheduler/Scheduler.hh b/Scheduler/Scheduler.hh index d72381837..5bb9443e9 100644 --- a/Scheduler/Scheduler.hh +++ b/Scheduler/Scheduler.hh @@ -50,8 +50,8 @@ namespace lib { // Types enum EventId { EV_NONE=0, - EV_READ=1, EV_WRITE=2, EV_HUP=4, EV_ERR=8, - EV_ALL=15 }; + EV_READ=1, EV_PRIO=2, EV_WRITE=4, EV_HUP=8, EV_ERR=16, + EV_ALL=31 }; typedef boost::function<void (int fd, EventId event)> Callback; /////////////////////////////////////////////////////////////////////////// @@ -69,8 +69,12 @@ namespace lib { ///@} /////////////////////////////////////////////////////////////////////////// - void set(int fd, Callback const & cb, EventId eventMask = EV_ALL); - void unset(int fd, EventId eventMask = EV_ALL); + void add(int fd, Callback const & cb, EventId eventMask = EV_ALL); + void remove(int fd, EventId eventMask = EV_ALL); + + void process(); + + void terminate(); protected: @@ -80,6 +84,7 @@ namespace lib { struct EventSpec { Callback cb_read; + Callback cb_prio; Callback cb_write; Callback cb_hup; Callback cb_err; @@ -91,12 +96,13 @@ namespace lib { FdTable fdTable_; int epollFd_; + bool terminate_; }; }} ///////////////////////////////hh.e//////////////////////////////////////// -//#include "Scheduler.cci" +#include "Scheduler.cci" //#include "Scheduler.ct" //#include "Scheduler.cti" #endif diff --git a/Scheduler/Scheduler.test.cc b/Scheduler/Scheduler.test.cc index 43b0931db..b22dda7d1 100644 --- a/Scheduler/Scheduler.test.cc +++ b/Scheduler/Scheduler.test.cc @@ -26,6 +26,16 @@ //#include "scheduler.test.ih" // Custom includes +#include <sys/types.h> +#include <signal.h> +#include <sys/wait.h> +#include <unistd.h> +#include <sys/socket.h> +#include <sys/un.h> +#include <errno.h> +#include <string.h> +#include <iostream> + #include "Scheduler.hh" #include <boost/test/auto_unit_test.hpp> @@ -36,9 +46,179 @@ using namespace satcom::lib; +namespace { + + char const * SOCK_PATH = "/tmp/sched_test.sock"; + + void error(char const * fn, char const * proc="") + { + std::cerr << "\n" << proc << fn << ": " << strerror(errno) << std::endl; + } + + void fail(char const * fn) + { + error(fn,"server: "); + _exit(1); + } + + void server() + { + int sock = socket(PF_UNIX,SOCK_STREAM,0); + if (sock<0) fail("socket"); + struct sockaddr_un sun; + memset(&sun,0,sizeof(sun)); + sun.sun_family = AF_UNIX; + strcpy(sun.sun_path,SOCK_PATH); + if (bind(sock,(struct sockaddr*)&sun,sizeof(sun))<0) fail("bind"); + if (listen(sock,1)<0) fail("listen"); + int conn = accept(sock,0,0); + if (conn < 0) fail("accept"); + + /////////////////////////////////////////////////////////////////////////// + + if (write(conn,"READ",4)<0) fail("write"); + char buffer[1024]; + int size = read(conn,buffer,1024); + if (size<0) fail("read"); + if (size == 5) { + buffer[5] = 0; + if (strcmp(buffer,"WRITE")==0) { + if (write(conn,"OK",2)<0) fail("write"); + } else + if (write(conn,"FAIL",4)<0) fail("write"); + } else + if (write(conn,"FAIL",4)<0) fail("write"); + + /////////////////////////////////////////////////////////////////////////// + + close(conn); + close(sock); + } + + int start_server() + { + unlink(SOCK_PATH); + int pid = fork(); + if (pid == 0) { + server(); + _exit(0); + } + if (pid < 0) { + error("fork"); + return 0; + } + + sleep(1); // Wait for the server socket to be opened + return pid; + } + + bool stop_server(int pid) + { + sleep(1); // Wait for the server to terminate + if (kill(pid,SIGTERM)<0) { + error("kill"); + return false; + } + int status = 0; + if (waitpid(pid,&status,0)<0) { + error("waitpid"); + return false; + } + unlink(SOCK_PATH); + if (WIFSIGNALED(status)) { + std::cerr << "\nserver terminated with signal " << WTERMSIG(status) << std::endl; + return false; + } + if (WEXITSTATUS(status)!=0) { + std::cerr << "\nserver terminated with exit status " << WEXITSTATUS(status) << std::endl; + return false; + } + return true; + } + + char buffer[1024]; + int size; + int event; + + void callback(int fd, Scheduler::EventId ev) + { + event = ev; + switch (event) { + case Scheduler::EV_READ: + size = recv(fd,buffer,1024,0); + break; + case Scheduler::EV_PRIO: + size = recv(fd,buffer,1024,MSG_OOB); + Scheduler::instance().terminate(); + break; + case Scheduler::EV_WRITE: + size = write(fd,buffer,size); + Scheduler::instance().terminate(); + break; + case Scheduler::EV_HUP: + case Scheduler::EV_ERR: + case Scheduler::EV_NONE: + case Scheduler::EV_ALL: + ; + } + Scheduler::instance().terminate(); + + } + +} + BOOST_AUTO_UNIT_TEST(scheduler) { + int pid = start_server(); + BOOST_REQUIRE (pid); + + int sock = socket(PF_UNIX,SOCK_STREAM,0); + if (sock<0) { + error("socket"); + BOOST_FAIL("socket"); + } + struct sockaddr_un sun; + memset(&sun,0,sizeof(sun)); + sun.sun_family = AF_UNIX; + strcpy(sun.sun_path,SOCK_PATH); + + if (connect(sock,(struct sockaddr*)&sun,sizeof(sun))<0) { + error("connect"); + BOOST_FAIL("connect"); + } + + /////////////////////////////////////////////////////////////////////////// + BOOST_CHECK_NO_THROW( Scheduler::instance() ); + + BOOST_CHECK_NO_THROW( Scheduler::instance().add(sock,&callback,Scheduler::EV_READ) ); + event = Scheduler::EV_NONE; + BOOST_CHECK_NO_THROW( Scheduler::instance().process() ); + BOOST_CHECK_EQUAL( event, Scheduler::EV_READ ); + BOOST_REQUIRE_EQUAL( size, 4 ); + buffer[size]=0; + BOOST_CHECK_EQUAL( buffer, "READ" ); + + BOOST_CHECK_NO_THROW( Scheduler::instance().add(sock,&callback,Scheduler::EV_WRITE) ); + strcpy(buffer,"WRITE"); + size=5; + event = Scheduler::EV_NONE; + BOOST_CHECK_NO_THROW( Scheduler::instance().process() ); + BOOST_CHECK_EQUAL( event, Scheduler::EV_WRITE ); + + BOOST_CHECK_NO_THROW( Scheduler::instance().remove(sock,Scheduler::EV_WRITE) ); + event = Scheduler::EV_NONE; + BOOST_CHECK_NO_THROW( Scheduler::instance().process() ); + BOOST_CHECK_EQUAL( event, Scheduler::EV_READ ); + BOOST_REQUIRE_EQUAL( size, 2 ); + buffer[size]=0; + BOOST_CHECK_EQUAL( buffer, "OK" ); + + /////////////////////////////////////////////////////////////////////////// + + close(sock); + + BOOST_CHECK (stop_server(pid)); } ///////////////////////////////cc.e//////////////////////////////////////// -- GitLab