39c0acfdbec2913790e01c1d840064e196ef21e9
[senf.git] / Scheduler / FdEvent.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 FdEvent.test unit tests */
25
26 //#include "FdEvent.test.hh"
27 //#include "FdEvent.test.ih"
28
29 // Custom includes
30 #include <sys/types.h>
31 #include <sys/stat.h>
32 #include <fcntl.h>
33 #include <sys/wait.h>
34 #include <unistd.h>
35 #include <sys/socket.h>
36 #include <sys/un.h>
37 #include <errno.h>
38 #include <string.h>
39 #include <iostream>
40
41 #include "FdEvent.hh"
42
43 #include <boost/bind.hpp>
44
45 #include "../Utils/auto_unit_test.hh"
46 #include <boost/test/test_tools.hpp>
47
48 #define prefix_
49 ///////////////////////////////cc.p////////////////////////////////////////
50
51 namespace {
52
53     char const * SOCK_PATH = "/tmp/sched_test.sock";
54
55     void error(char const * fn, char const * proc="")
56     {
57         std::cerr << "\n" << proc << fn << ": " << strerror(errno) << std::endl;
58     }
59
60     void fail(char const * fn)
61     {
62         error(fn,"server: ");
63         _exit(1);
64     }
65
66     void server()
67     {
68         int sock = socket(PF_UNIX,SOCK_STREAM,0);
69         if (sock<0) fail("socket");
70         struct sockaddr_un sun;
71         memset(&sun,0,sizeof(sun));
72         sun.sun_family = AF_UNIX;
73         strcpy(sun.sun_path,SOCK_PATH);
74         if (bind(sock,(struct sockaddr*)&sun,sizeof(sun))<0) fail("bind");
75         if (listen(sock,1)<0) fail("listen");
76         int conn = accept(sock,0,0);
77         if (conn < 0) fail("accept");
78
79         ///////////////////////////////////////////////////////////////////////////
80
81         if (write(conn,"READ",4)<0) fail("write");
82         char buffer[1024];
83         int size =  read(conn,buffer,1024);
84         if (size<0) fail("read");
85         if (size == 5) {
86             buffer[5] = 0;
87             if (strcmp(buffer,"WRITE")==0) {
88                 if (write(conn,"OK",2)<0) fail("write");
89             } else
90                 if (write(conn,"FAIL",4)<0) fail("write");
91         } else
92             if (write(conn,"FAIL",4)<0) fail("write");
93
94         ///////////////////////////////////////////////////////////////////////////
95
96         close(conn);
97         close(sock);
98     }
99
100     int start_server()
101     {
102         unlink(SOCK_PATH);
103         int pid = fork();
104         if (pid == 0) {
105             server();
106             _exit(0);
107         }
108         if (pid < 0) {
109             error("fork");
110             return 0;
111         }
112
113         sleep(1); // Wait for the server socket to be opened
114         return pid;
115     }
116
117     bool stop_server(int pid)
118     {
119         sleep(1); // Wait for the server to terminate
120         if (kill(pid,SIGTERM)<0) {
121             error("kill");
122             return false;
123         }
124         int status = 0;
125         if (waitpid(pid,&status,0)<0) {
126             error("waitpid");
127             return false;
128         }
129         unlink(SOCK_PATH);
130         if (WIFSIGNALED(status)) {
131             std::cerr << "\nserver terminated with signal " << WTERMSIG(status) << std::endl;
132             return false;
133         }
134         if (WEXITSTATUS(status)!=0) {
135             std::cerr << "\nserver terminated with exit status " << WEXITSTATUS(status) << std::endl;
136             return false;
137         }
138         return true;
139     }
140
141     char buffer[1024];
142     int size (0);
143     int event (0);
144     int calls (0);
145
146     void callback(int fd, int ev)
147     {
148         ++calls;
149         event = ev;
150         switch (event & senf::scheduler::FdEvent::EV_ALL) {
151         case senf::scheduler::FdEvent::EV_READ:
152             size = recv(fd,buffer,1024,0);
153             break;
154         case senf::scheduler::FdEvent::EV_PRIO:
155             size = recv(fd,buffer,1024,MSG_OOB);
156             break;
157         case senf::scheduler::FdEvent::EV_WRITE:
158             size = write(fd,buffer,size);
159             break;
160         }
161     }
162
163 }
164
165 BOOST_AUTO_UNIT_TEST(fdDispatcher)
166 {
167     senf::scheduler::FdManager::instance().timeout(1000);
168
169     int pid (start_server());
170     BOOST_REQUIRE( pid );
171
172     int sock = socket(PF_UNIX,SOCK_STREAM,0);
173     if (sock<0) {
174         error("socket");
175         BOOST_FAIL("socket");
176     }
177     struct sockaddr_un sun;
178     memset(&sun,0,sizeof(sun));
179     sun.sun_family = AF_UNIX;
180     strcpy(sun.sun_path,SOCK_PATH);
181
182     if (connect(sock,(struct sockaddr*)&sun,sizeof(sun))<0) {
183         error("connect");
184         BOOST_FAIL("connect");
185     }
186     
187     {
188         senf::scheduler::FdEvent sockread ("testHandler",  boost::bind(&callback, sock, _1),
189                                            sock, senf::scheduler::FdEvent::EV_READ);
190         senf::scheduler::FdEvent sockwrite ("testHandler", boost::bind(&callback, sock, _1),
191                                             sock, senf::scheduler::FdEvent::EV_WRITE, false);
192         event = 0;
193         SENF_CHECK_NO_THROW( senf::scheduler::FdManager::instance().processOnce() );
194         SENF_CHECK_NO_THROW( senf::scheduler::FIFORunner::instance().run() );
195         BOOST_CHECK_EQUAL( event, senf::scheduler::FdEvent::EV_READ );
196         BOOST_CHECK_EQUAL( size, 4 );
197         buffer[size] = 0;
198         BOOST_CHECK_EQUAL( buffer, "READ" );
199
200         strcpy(buffer,"WRITE");
201         size=5;
202         SENF_CHECK_NO_THROW( sockwrite.enable() );
203         event = 0;
204         sleep(1);
205         SENF_CHECK_NO_THROW( senf::scheduler::FdManager::instance().processOnce() );
206         SENF_CHECK_NO_THROW( senf::scheduler::FIFORunner::instance().run() );
207         BOOST_CHECK_EQUAL( event, senf::scheduler::FdEvent::EV_WRITE );
208
209         SENF_CHECK_NO_THROW( sockwrite.disable() );
210         event = 0;
211         sleep(1);
212         SENF_CHECK_NO_THROW( senf::scheduler::FdManager::instance().processOnce() );
213         SENF_CHECK_NO_THROW( senf::scheduler::FIFORunner::instance().run() );
214         BOOST_CHECK_EQUAL( event, senf::scheduler::FdEvent::EV_HUP | senf::scheduler::FdEvent::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( senf::scheduler::FIFORunner::instance().run() );
221         BOOST_CHECK_EQUAL( calls, 3 );
222     
223         // Ensure, removing an already closed file-descriptor doesn't wreak havoc
224         close(sock);
225     }
226
227     SENF_CHECK_NO_THROW( senf::scheduler::FIFORunner::instance().run() );
228     BOOST_CHECK_EQUAL( calls, 3 );
229
230     BOOST_CHECK (stop_server(pid));
231 }
232
233 namespace {
234
235     bool is_close(senf::ClockService::clock_type a, senf::ClockService::clock_type b)
236     {
237         return (a<b ? b-a : a-b) < senf::ClockService::milliseconds(100);
238     }
239
240     bool called (false);
241     void handler(int events)
242     {
243         called=true;
244     }
245 }
246
247 BOOST_AUTO_UNIT_TEST(fileDispatcher)
248 {
249     senf::scheduler::detail::FileDispatcher::instance().timeout(500);
250
251     int fd (open("test.empty.file", O_RDWR|O_CREAT|O_TRUNC, 0600));
252     
253     senf::ClockService::clock_type t (senf::ClockService::now());
254     try {
255         senf::scheduler::FdEvent fde ("testHandler", &handler, 
256                                       fd, senf::scheduler::FdEvent::EV_READ);
257         SENF_CHECK_NO_THROW( senf::scheduler::FdManager::instance().processOnce() );
258         SENF_CHECK_NO_THROW( senf::scheduler::detail::FileDispatcher::instance().prepareRun() );
259         SENF_CHECK_NO_THROW( senf::scheduler::FIFORunner::instance().run() );
260         
261         BOOST_CHECK( called );
262         BOOST_CHECK_PREDICATE( is_close, (t)(senf::ClockService::now()) );
263     }
264     catch (std::exception const & ex) {
265         std::cerr << "Exception:\n" << ex.what() << "\n";
266         throw;
267     }
268     close(fd);
269
270     called = false;
271     t = senf::ClockService::now();
272     SENF_CHECK_NO_THROW( senf::scheduler::FdManager::instance().processOnce() );
273     SENF_CHECK_NO_THROW( senf::scheduler::detail::FileDispatcher::instance().prepareRun() );
274     SENF_CHECK_NO_THROW( senf::scheduler::FIFORunner::instance().run() );
275
276     BOOST_CHECK( ! called );
277     BOOST_CHECK_PREDICATE( 
278         is_close, (t+senf::ClockService::milliseconds(500))(senf::ClockService::now()) );
279
280     unlink("test.empty.file");
281     senf::scheduler::detail::FileDispatcher::instance().timeout(-1);
282 }
283
284 ///////////////////////////////cc.e////////////////////////////////////////
285 #undef prefix_
286
287 \f
288 // Local Variables:
289 // mode: c++
290 // fill-column: 100
291 // comment-column: 40
292 // c-file-style: "senf"
293 // indent-tabs-mode: nil
294 // ispell-local-dictionary: "american"
295 // compile-command: "scons -u test"
296 // End: