switch to new MPL based Fraunhofer FOKUS Public License
[senf.git] / senf / Utils / Daemon / Daemon.test.cc
1 // $Id$
2 //
3 // Copyright (C) 2007
4 // Fraunhofer Institute for Open Communication Systems (FOKUS)
5 //
6 // The contents of this file are subject to the Fraunhofer FOKUS Public License
7 // Version 1.0 (the "License"); you may not use this file except in compliance
8 // with the License. You may obtain a copy of the License at 
9 // http://senf.berlios.de/license.html
10 //
11 // The Fraunhofer FOKUS Public License Version 1.0 is based on, 
12 // but modifies the Mozilla Public License Version 1.1.
13 // See the full license text for the amendments.
14 //
15 // Software distributed under the License is distributed on an "AS IS" basis, 
16 // WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License 
17 // for the specific language governing rights and limitations under the License.
18 //
19 // The Original Code is Fraunhofer FOKUS code.
20 //
21 // The Initial Developer of the Original Code is Fraunhofer-Gesellschaft e.V. 
22 // (registered association), Hansastraße 27 c, 80686 Munich, Germany.
23 // All Rights Reserved.
24 //
25 // Contributor(s):
26 //   Stefan Bund <g0dil@berlios.de>
27
28 /** \file
29     \brief Daemon unit tests */
30
31 //#include "Daemon.test.hh"
32 //#include "Daemon.test.ih"
33
34 // Custom includes
35 #include <unistd.h>
36 #include <sys/types.h>
37 #include <sys/wait.h>
38 #include <iostream>
39 #include <fstream>
40 #include <boost/filesystem/operations.hpp>
41 #include "Daemon.hh"
42 #include <senf/Utils/Exception.hh>
43 #include <senf/Utils/Backtrace.hh>
44 #include <senf/Scheduler/Scheduler.hh>
45
46 #include <senf/Utils/auto_unit_test.hh>
47 #include <boost/test/test_tools.hpp>
48
49 #define prefix_
50 //-/////////////////////////////////////////////////////////////////////////////////////////////////
51
52 namespace {
53
54     void delay(unsigned long milliseconds)
55     {
56         struct timespec ts;
57         ts.tv_sec = milliseconds / 1000;
58         ts.tv_nsec = (milliseconds % 1000) * 1000000;
59         while (nanosleep(&ts,&ts) < 0 && errno == EINTR) ;
60     }
61
62     class MyDaemon : public senf::Daemon
63     {
64         void configure() {
65             std::cout << "Running configure()" << std::endl;
66             pidFile("invalid.pid");
67             consoleLog("invalid.log");
68             senf::Daemon::configure();
69         }
70
71         void init() {
72             std::cout << "Running init()" << std::endl;
73             std::cerr << "(stderr)" << std::endl;
74         }
75
76         void run() {
77             std::cout << "Running run()" << std::endl;
78             delay(2000);
79         }
80     };
81
82     int myMain(int argc, char const ** argv)
83     {
84         MyDaemon instance;
85         return instance.start(argc, argv);
86     }
87
88     int pid;
89
90     void backtrace(int)
91     {
92         senf::backtrace(std::cerr, 100);
93         ::signal(SIGABRT, SIG_DFL);
94         ::kill(::getpid(), SIGABRT);
95     };
96
97     int run(int argc, char const ** argv)
98     {
99         pid  = ::fork();
100         if (pid < 0) throw senf::SystemException("::fork()");
101         if (pid == 0) {
102             signal(SIGABRT, &backtrace);
103             signal(SIGCHLD, SIG_IGN);
104             try {
105                 ::_exit(myMain(argc, argv));
106             } catch (std::exception & ex) {
107                 std::cerr << "Unexpected exception: " << ex.what() << std::endl;
108             } catch (...) {
109                 std::cerr << "Unexpected exception" << std::endl;
110             }
111             ::_exit(125);
112         }
113         signal(SIGCHLD, SIG_DFL);
114         int status;
115         if (::waitpid(pid, &status, 0) < 0)
116             throw senf::SystemException("::waitpid()");
117         if (WIFSIGNALED(status))
118             std::cerr << "Terminated with signal "
119                       << senf::signalName(WTERMSIG(status)) << "(" << WTERMSIG(status) << ")\n";
120         else if (WIFEXITED(status))
121             std::cerr << "Exited normally with exit status " << WEXITSTATUS(status) << "\n";
122         return status;
123     }
124
125 }
126
127 SENF_AUTO_UNIT_TEST(testDaemon)
128 {
129     char const * args[] = { "run",
130                             "--console-log=testDaemon.log",
131                             "--pid-file=testDaemon.pid" };
132
133     SENF_CHECK_NO_THROW( BOOST_CHECK_EQUAL( run(sizeof(args)/sizeof(*args), args), 0 ) );
134
135     BOOST_CHECK( ! boost::filesystem::exists("invalid.log") );
136     BOOST_CHECK( ! boost::filesystem::exists("invalid.pid") );
137     BOOST_CHECK( boost::filesystem::exists("testDaemon.pid") );
138     BOOST_REQUIRE( boost::filesystem::exists("testDaemon.log") );
139
140     boost::filesystem::rename("testDaemon.log", "testDaemon.log.1");
141     {
142         std::ifstream pidFile ("testDaemon.pid");
143         int pid (0);
144         BOOST_CHECK( pidFile >> pid );
145         BOOST_CHECK( pid != 0 );
146         if (pid != 0)
147             ::kill(pid, SIGHUP);
148     }
149
150     delay(3000);
151     BOOST_CHECK( ! boost::filesystem::exists("testDaemon.pid") );
152     BOOST_CHECK( boost::filesystem::exists("testDaemon.log") );
153     BOOST_CHECK( boost::filesystem::exists("testDaemon.log.1") );
154
155     std::ifstream log ("testDaemon.log.1");
156     std::stringstream data;
157     data << log.rdbuf();
158     BOOST_CHECK_EQUAL( data.str(), "Running init()\n(stderr)\nRunning run()\n" );
159     SENF_CHECK_NO_THROW( boost::filesystem::remove("testDaemon.log") );
160     SENF_CHECK_NO_THROW( boost::filesystem::remove("testDaemon.log.1") );
161 }
162
163 //-/////////////////////////////////////////////////////////////////////////////////////////////////
164 #undef prefix_
165
166 \f
167 // Local Variables:
168 // mode: c++
169 // fill-column: 100
170 // comment-column: 40
171 // c-file-style: "senf"
172 // indent-tabs-mode: nil
173 // ispell-local-dictionary: "american"
174 // compile-command: "scons -u test"
175 // End: