Skip to content
Snippets Groups Projects
Scheduler.test.cc 7.48 KiB
Newer Older
sbund's avatar
sbund committed
// $Id$
//
// Copyright (C) 2006
sbund's avatar
sbund committed
// 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.

// Unit tests

//#include "scheduler.test.hh"
//#include "scheduler.test.ih"

// Custom includes
sbund's avatar
sbund committed
#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>

sbund's avatar
sbund committed
#include "Scheduler.hh"
sbund's avatar
sbund committed

#include <boost/test/auto_unit_test.hpp>
#include <boost/test/test_tools.hpp>

#define prefix_
///////////////////////////////cc.p////////////////////////////////////////

using namespace senf;
sbund's avatar
sbund committed

sbund's avatar
sbund committed
namespace {
sbund's avatar
sbund committed
    char const * SOCK_PATH = "/tmp/sched_test.sock";
sbund's avatar
sbund committed
    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;
        }
sbund's avatar
sbund committed
        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;
g0dil's avatar
g0dil committed
        switch (event & Scheduler::EV_ALL) {
sbund's avatar
sbund committed
        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;
        }
        Scheduler::instance().terminate();
    }
    void timeout()
g0dil's avatar
g0dil committed
    {
        Scheduler::instance().terminate();
g0dil's avatar
g0dil committed
    }
    struct HandleWrapper
    {
        HandleWrapper(int fd,std::string const & tag) : fd_(fd), tag_(tag) {}
        int fd_;
        std::string tag_;
    };

    int retrieve_filehandle(HandleWrapper const & handle)
    {
        return handle.fd_;
    }

    void handleCallback(HandleWrapper const & handle, Scheduler::EventId event)
    {
        if (handle.tag_ != "TheTag")
            return;
        callback(handle.fd_,event);
    }
g0dil's avatar
g0dil committed

    bool is_close(MicroTime a, MicroTime b)
    {
        return (a<b ? b-a : a-b) < 10100; // a little bit over 10ms
g0dil's avatar
g0dil committed
    }
sbund's avatar
sbund committed
}

sbund's avatar
sbund committed
BOOST_AUTO_UNIT_TEST(scheduler)
{
sbund's avatar
sbund committed
    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);
sbund's avatar
sbund committed
    if (connect(sock,(struct sockaddr*)&sun,sizeof(sun))<0) {
        error("connect");
        BOOST_FAIL("connect");
    }

    ///////////////////////////////////////////////////////////////////////////

sbund's avatar
sbund committed
    BOOST_CHECK_NO_THROW( Scheduler::instance() );
sbund's avatar
sbund committed

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

g0dil's avatar
g0dil committed
    BOOST_CHECK_NO_THROW( Scheduler::instance().timeout(100,&timeout) );
    BOOST_CHECK_NO_THROW( Scheduler::instance().timeout(200,&timeout) );
    MicroTime t (now());
    BOOST_CHECK_NO_THROW( Scheduler::instance().process() );
    BOOST_CHECK_PREDICATE( is_close, (now()) (t+100*1000) );
    BOOST_CHECK_NO_THROW( Scheduler::instance().process() );
    BOOST_CHECK_PREDICATE( is_close, (now()) (t+200*1000) );
    HandleWrapper handle(sock,"TheTag");
    BOOST_CHECK_NO_THROW( Scheduler::instance().add(handle,&handleCallback,Scheduler::EV_WRITE) );
sbund's avatar
sbund committed
    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(handle,Scheduler::EV_WRITE) );
sbund's avatar
sbund committed
    event = Scheduler::EV_NONE;
    BOOST_CHECK_NO_THROW( Scheduler::instance().process() );
g0dil's avatar
g0dil committed
    BOOST_CHECK_EQUAL( event, Scheduler::EventId(Scheduler::EV_READ|Scheduler::EV_HUP) );
sbund's avatar
sbund committed
    BOOST_REQUIRE_EQUAL( size, 2 );
    buffer[size]=0;
    BOOST_CHECK_EQUAL( buffer, "OK" );

    ///////////////////////////////////////////////////////////////////////////

    close(sock);

    BOOST_CHECK (stop_server(pid));
sbund's avatar
sbund committed
}

///////////////////////////////cc.e////////////////////////////////////////
#undef prefix_


// Local Variables:
// mode: c++
// fill-column: 100
// c-file-style: "senf"
// indent-tabs-mode: nil
// ispell-local-dictionary: "american"
// compile-command: "scons -u test"
// comment-column: 40
sbund's avatar
sbund committed
// End: