Fix documentation build under maverick (doxygen 1.7.1)
[senf.git] / senf / 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 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 <senf/Utils/auto_unit_test.hh>
46 #include <boost/test/test_tools.hpp>
47
48 #define prefix_
49 //-/////////////////////////////////////////////////////////////////////////////////////////////////
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             signal(SIGCHLD, SIG_IGN);
106             server();
107             _exit(0);
108         }
109         if (pid < 0) {
110             error("fork");
111             return 0;
112         }
113         signal(SIGCHLD, SIG_DFL);
114
115         sleep(1); // Wait for the server socket to be opened
116         return pid;
117     }
118
119     bool stop_server(int pid)
120     {
121         sleep(1); // Wait for the server to terminate
122         if (kill(pid,SIGTERM)<0) {
123             error("kill");
124             return false;
125         }
126         int status = 0;
127         if (waitpid(pid,&status,0)<0) {
128             error("waitpid");
129             return false;
130         }
131         unlink(SOCK_PATH);
132         if (WIFSIGNALED(status)) {
133             std::cerr << "\nserver terminated with signal " << WTERMSIG(status) << std::endl;
134             return false;
135         }
136         if (WEXITSTATUS(status)!=0) {
137             std::cerr << "\nserver terminated with exit status " << WEXITSTATUS(status) << std::endl;
138             return false;
139         }
140         return true;
141     }
142
143     char buffer[1024];
144     int size (0);
145     int event (0);
146     int calls (0);
147
148     void callback(int fd, int ev)
149     {
150         ++calls;
151         event = ev;
152         switch (event & senf::scheduler::FdEvent::EV_ALL) {
153         case senf::scheduler::FdEvent::EV_READ:
154             size = recv(fd,buffer,1024,0);
155             break;
156         case senf::scheduler::FdEvent::EV_PRIO:
157             size = recv(fd,buffer,1024,MSG_OOB);
158             break;
159         case senf::scheduler::FdEvent::EV_WRITE:
160             size = write(fd,buffer,size);
161             break;
162         }
163     }
164
165 }
166
167 SENF_AUTO_UNIT_TEST(fdDispatcher)
168 {
169     senf::scheduler::detail::FdManager::instance().timeout(1000);
170
171     int pid (start_server());
172     BOOST_REQUIRE( pid );
173
174     int sock = socket(PF_UNIX,SOCK_STREAM,0);
175     if (sock<0) {
176         error("socket");
177         BOOST_FAIL("socket");
178     }
179     struct sockaddr_un sun;
180     memset(&sun,0,sizeof(sun));
181     sun.sun_family = AF_UNIX;
182     strcpy(sun.sun_path,SOCK_PATH);
183
184     if (connect(sock,(struct sockaddr*)&sun,sizeof(sun))<0) {
185         error("connect");
186         BOOST_FAIL("connect");
187     }
188
189     {
190         senf::scheduler::FdEvent sockread ("testHandler",  boost::bind(&callback, sock, _1),
191                                            sock, senf::scheduler::FdEvent::EV_READ);
192         senf::scheduler::FdEvent sockwrite ("testHandler", boost::bind(&callback, sock, _1),
193                                             sock, senf::scheduler::FdEvent::EV_WRITE, false);
194         event = 0;
195         SENF_CHECK_NO_THROW( senf::scheduler::detail::FdManager::instance().processOnce() );
196         SENF_CHECK_NO_THROW( senf::scheduler::detail::FIFORunner::instance().run() );
197         BOOST_CHECK_EQUAL( event, senf::scheduler::FdEvent::EV_READ );
198         BOOST_CHECK_EQUAL( size, 4 );
199         buffer[size] = 0;
200         BOOST_CHECK_EQUAL( buffer, "READ" );
201
202         strcpy(buffer,"WRITE");
203         size=5;
204         SENF_CHECK_NO_THROW( sockwrite.enable() );
205         event = 0;
206         sleep(1);
207         SENF_CHECK_NO_THROW( senf::scheduler::detail::FdManager::instance().processOnce() );
208         SENF_CHECK_NO_THROW( senf::scheduler::detail::FIFORunner::instance().run() );
209         BOOST_CHECK_EQUAL( event, senf::scheduler::FdEvent::EV_WRITE );
210
211         SENF_CHECK_NO_THROW( sockwrite.disable() );
212         event = 0;
213         sleep(1);
214         SENF_CHECK_NO_THROW( senf::scheduler::detail::FdManager::instance().processOnce() );
215         SENF_CHECK_NO_THROW( senf::scheduler::detail::FIFORunner::instance().run() );
216         BOOST_CHECK_EQUAL( event, senf::scheduler::FdEvent::EV_HUP | senf::scheduler::FdEvent::EV_READ );
217         BOOST_CHECK_EQUAL( size, 2 );
218         buffer[size]=0;
219         BOOST_CHECK_EQUAL( buffer, "OK" );
220
221         BOOST_CHECK_EQUAL( calls, 3 );
222         SENF_CHECK_NO_THROW( senf::scheduler::detail::FIFORunner::instance().run() );
223         BOOST_CHECK_EQUAL( calls, 3 );
224
225         // Ensure, removing an already closed file-descriptor doesn't wreak havoc
226         close(sock);
227     }
228
229     SENF_CHECK_NO_THROW( senf::scheduler::detail::FIFORunner::instance().run() );
230     BOOST_CHECK_EQUAL( calls, 3 );
231
232     BOOST_CHECK (stop_server(pid));
233 }
234
235 namespace {
236
237     bool is_close(senf::ClockService::clock_type a, senf::ClockService::clock_type b)
238     {
239         return (a<b ? b-a : a-b) < senf::ClockService::milliseconds(50);
240     }
241
242     bool called (false);
243     void handler(int events)
244     {
245         called=true;
246     }
247 }
248
249 SENF_AUTO_UNIT_TEST(fileDispatcher)
250 {
251     char const * enabled (getenv("SENF_TIMING_CRITICAL_TESTS"));
252     BOOST_WARN_MESSAGE(enabled, "Set SENF_TIMING_CRITICAL_TESTS to not skip timing critical tests");
253
254     senf::scheduler::detail::FileDispatcher::instance().timeout(500);
255
256     int fd (open("test.empty.file", O_RDWR|O_CREAT|O_TRUNC, 0600));
257
258     senf::ClockService::clock_type t (senf::ClockService::now());
259     try {
260         senf::scheduler::FdEvent fde ("testHandler", &handler,
261                                       fd, senf::scheduler::FdEvent::EV_READ);
262         SENF_CHECK_NO_THROW( senf::scheduler::detail::FdManager::instance().processOnce() );
263         SENF_CHECK_NO_THROW( senf::scheduler::detail::FileDispatcher::instance().prepareRun() );
264         SENF_CHECK_NO_THROW( senf::scheduler::detail::FIFORunner::instance().run() );
265
266         BOOST_CHECK( called );
267         if (enabled)
268             BOOST_CHECK_PREDICATE( is_close, (t)(senf::ClockService::now()) );
269     }
270     catch (std::exception const & ex) {
271         std::cerr << "Exception:\n" << ex.what() << "\n";
272         throw;
273     }
274     close(fd);
275
276     called = false;
277     t = senf::ClockService::now();
278     SENF_CHECK_NO_THROW( senf::scheduler::detail::FdManager::instance().processOnce() );
279     SENF_CHECK_NO_THROW( senf::scheduler::detail::FileDispatcher::instance().prepareRun() );
280     SENF_CHECK_NO_THROW( senf::scheduler::detail::FIFORunner::instance().run() );
281
282     BOOST_CHECK( ! called );
283     if (enabled)
284         BOOST_CHECK_PREDICATE(
285             is_close, (t+senf::ClockService::milliseconds(500))(senf::ClockService::now()) );
286
287     unlink("test.empty.file");
288     senf::scheduler::detail::FileDispatcher::instance().timeout(-1);
289 }
290
291 //-/////////////////////////////////////////////////////////////////////////////////////////////////
292 #undef prefix_
293
294 \f
295 // Local Variables:
296 // mode: c++
297 // fill-column: 100
298 // comment-column: 40
299 // c-file-style: "senf"
300 // indent-tabs-mode: nil
301 // ispell-local-dictionary: "american"
302 // compile-command: "scons -u test"
303 // End: