62a618780b06a62a808ae2be388c6097986248a6
[senf.git] / Scheduler / FdDispatcher.test.cc
1 // $Id$
2 //
3 // Copyright (C) 2008 
4 // Fraunhofer Institute for Open Communication Systems (FOKUS)
5 // Competence Center NETwork research (NET), St. Augustin, GERMANY
6 //     Stefan Bund <g0dil@berlios.de>
7 //
8 // This program is free software; you can redistribute it and/or modify
9 // it under the terms of the GNU General Public License as published by
10 // the Free Software Foundation; either version 2 of the License, or
11 // (at your option) any later version.
12 //
13 // This program is distributed in the hope that it will be useful,
14 // but WITHOUT ANY WARRANTY; without even the implied warranty of
15 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16 // GNU General Public License for more details.
17 //
18 // You should have received a copy of the GNU General Public License
19 // along with this program; if not, write to the
20 // Free Software Foundation, Inc.,
21 // 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
22
23 /** \file
24     \brief FdDispatcher.test unit tests */
25
26 //#include "FdDispatcher.test.hh"
27 //#include "FdDispatcher.test.ih"
28
29 // Custom includes
30 #include <sys/types.h>
31 #include <signal.h>
32 #include <sys/wait.h>
33 #include <unistd.h>
34 #include <sys/socket.h>
35 #include <sys/un.h>
36 #include <errno.h>
37 #include <string.h>
38 #include <iostream>
39
40 #include "FdDispatcher.hh"
41
42 #include <boost/bind.hpp>
43
44 #include "../Utils/auto_unit_test.hh"
45 #include <boost/test/test_tools.hpp>
46
47 #define prefix_
48 ///////////////////////////////cc.p////////////////////////////////////////
49
50 namespace {
51
52     char const * SOCK_PATH = "/tmp/sched_test.sock";
53
54     void error(char const * fn, char const * proc="")
55     {
56         std::cerr << "\n" << proc << fn << ": " << strerror(errno) << std::endl;
57     }
58
59     void fail(char const * fn)
60     {
61         error(fn,"server: ");
62         _exit(1);
63     }
64
65     void server()
66     {
67         int sock = socket(PF_UNIX,SOCK_STREAM,0);
68         if (sock<0) fail("socket");
69         struct sockaddr_un sun;
70         memset(&sun,0,sizeof(sun));
71         sun.sun_family = AF_UNIX;
72         strcpy(sun.sun_path,SOCK_PATH);
73         if (bind(sock,(struct sockaddr*)&sun,sizeof(sun))<0) fail("bind");
74         if (listen(sock,1)<0) fail("listen");
75         int conn = accept(sock,0,0);
76         if (conn < 0) fail("accept");
77
78         ///////////////////////////////////////////////////////////////////////////
79
80         if (write(conn,"READ",4)<0) fail("write");
81         char buffer[1024];
82         int size =  read(conn,buffer,1024);
83         if (size<0) fail("read");
84         if (size == 5) {
85             buffer[5] = 0;
86             if (strcmp(buffer,"WRITE")==0) {
87                 if (write(conn,"OK",2)<0) fail("write");
88             } else
89                 if (write(conn,"FAIL",4)<0) fail("write");
90         } else
91             if (write(conn,"FAIL",4)<0) fail("write");
92
93         ///////////////////////////////////////////////////////////////////////////
94
95         close(conn);
96         close(sock);
97     }
98
99     int start_server()
100     {
101         unlink(SOCK_PATH);
102         int pid = fork();
103         if (pid == 0) {
104             server();
105             _exit(0);
106         }
107         if (pid < 0) {
108             error("fork");
109             return 0;
110         }
111
112         sleep(1); // Wait for the server socket to be opened
113         return pid;
114     }
115
116     bool stop_server(int pid)
117     {
118         sleep(1); // Wait for the server to terminate
119         if (kill(pid,SIGTERM)<0) {
120             error("kill");
121             return false;
122         }
123         int status = 0;
124         if (waitpid(pid,&status,0)<0) {
125             error("waitpid");
126             return false;
127         }
128         unlink(SOCK_PATH);
129         if (WIFSIGNALED(status)) {
130             std::cerr << "\nserver terminated with signal " << WTERMSIG(status) << std::endl;
131             return false;
132         }
133         if (WEXITSTATUS(status)!=0) {
134             std::cerr << "\nserver terminated with exit status " << WEXITSTATUS(status) << std::endl;
135             return false;
136         }
137         return true;
138     }
139
140     char buffer[1024];
141     int size (0);
142     int event (0);
143     int calls (0);
144
145     void callback(int fd, int ev)
146     {
147         ++calls;
148         event = ev;
149         switch (event & senf::scheduler::FdDispatcher::EV_ALL) {
150         case senf::scheduler::FdDispatcher::EV_READ:
151             size = recv(fd,buffer,1024,0);
152             break;
153         case senf::scheduler::FdDispatcher::EV_PRIO:
154             size = recv(fd,buffer,1024,MSG_OOB);
155             break;
156         case senf::scheduler::FdDispatcher::EV_WRITE:
157             size = write(fd,buffer,size);
158             break;
159         }
160     }
161
162 }
163
164 BOOST_AUTO_UNIT_TEST(fdDispatcher)
165 {
166     senf::scheduler::FdManager manager;
167     senf::scheduler::FIFORunner runner;
168     senf::scheduler::FdDispatcher dispatcher (manager, runner);
169
170     int pid (start_server());
171     BOOST_REQUIRE( pid );
172
173     int sock = socket(PF_UNIX,SOCK_STREAM,0);
174     if (sock<0) {
175         error("socket");
176         BOOST_FAIL("socket");
177     }
178     struct sockaddr_un sun;
179     memset(&sun,0,sizeof(sun));
180     sun.sun_family = AF_UNIX;
181     strcpy(sun.sun_path,SOCK_PATH);
182
183     if (connect(sock,(struct sockaddr*)&sun,sizeof(sun))<0) {
184         error("connect");
185         BOOST_FAIL("connect");
186     }
187
188     SENF_CHECK_NO_THROW( dispatcher.add(sock, boost::bind(&callback, sock, _1),
189                                         senf::scheduler::FdDispatcher::EV_READ) );
190     manager.timeout(1000);
191     event = 0;
192     SENF_CHECK_NO_THROW( manager.processOnce() );
193     SENF_CHECK_NO_THROW( runner.run() );
194     BOOST_CHECK_EQUAL( event, senf::scheduler::FdDispatcher::EV_READ );
195     BOOST_CHECK_EQUAL( size, 4 );
196     buffer[size] = 0;
197     BOOST_CHECK_EQUAL( buffer, "READ" );
198
199     strcpy(buffer,"WRITE");
200     size=5;
201     SENF_CHECK_NO_THROW( dispatcher.add(sock, boost::bind(&callback, sock, _1),
202                                         senf::scheduler::FdDispatcher::EV_WRITE) );
203     event = 0;
204     sleep(1);
205     SENF_CHECK_NO_THROW( manager.processOnce() );
206     SENF_CHECK_NO_THROW( runner.run() );
207     BOOST_CHECK_EQUAL( event, senf::scheduler::FdDispatcher::EV_WRITE );
208
209     SENF_CHECK_NO_THROW( dispatcher.remove(sock, senf::scheduler::FdDispatcher::EV_WRITE) );
210     event = 0;
211     sleep(1);
212     SENF_CHECK_NO_THROW( manager.processOnce() );
213     SENF_CHECK_NO_THROW( runner.run() );
214     BOOST_CHECK_EQUAL( event, senf::scheduler::FdDispatcher::EV_HUP | senf::scheduler::FdDispatcher::EV_READ );
215     BOOST_CHECK_EQUAL( size, 2 );
216     buffer[size]=0;
217     BOOST_CHECK_EQUAL( buffer, "OK" );
218
219     BOOST_CHECK_EQUAL( calls, 3 );
220     SENF_CHECK_NO_THROW( runner.run() );
221     BOOST_CHECK_EQUAL( calls, 3 );
222     
223     // Ensure, removing an already closed file-descriptor doesn't wreak havoc
224     close(sock);
225     SENF_CHECK_NO_THROW( dispatcher.remove(sock) );
226
227     SENF_CHECK_NO_THROW( runner.run() );
228     BOOST_CHECK_EQUAL( calls, 3 );
229
230
231     BOOST_CHECK (stop_server(pid));
232 }
233
234 ///////////////////////////////cc.e////////////////////////////////////////
235 #undef prefix_
236
237 \f
238 // Local Variables:
239 // mode: c++
240 // fill-column: 100
241 // comment-column: 40
242 // c-file-style: "senf"
243 // indent-tabs-mode: nil
244 // ispell-local-dictionary: "american"
245 // compile-command: "scons -u test"
246 // End: