1 #ifndef TUT_FORK_H_GUARD
2 #define TUT_FORK_H_GUARD
3 #include <tut/tut_config.hpp>
5 #if defined(TUT_USE_POSIX)
11 #include <sys/types.h>
19 #include "tut_result.hpp"
20 #include "tut_assert.hpp"
21 #include "tut_runner.hpp"
26 template<
typename,
int>
32 class test_group_posix
35 template<
typename,
int>
36 friend class test_group;
39 void send_result_(
const T *obj,
const test_result &tr)
41 if(obj->get_pipe_() == -1)
48 std::ostringstream ss;
49 ss << int(tr.result) <<
"\n"
53 << tr.exception_typeid <<
"\n";
54 std::copy( tr.message.begin(), tr.message.end(), std::ostreambuf_iterator<char>(ss.rdbuf()) );
56 int size = ss.str().length();
57 int w = write(obj->get_pipe_(), ss.str().c_str(), size);
58 ensure_errno(
"write() failed", w == size);
62 virtual ~test_group_posix()
73 ensure(
"trying to call 'tut_fork' in ctor of test object",
self != NULL);
78 pid_t waitpid(pid_t pid,
int *status,
int flags = 0)
81 ensure(
"trying to call 'tut_waitpid' in ctor of test object",
self != NULL);
83 return self->waitpid_(pid, status, flags);
86 void ensure_child_exit(pid_t pid,
int exit_status = 0)
89 ensure(
"trying to call 'ensure_child_exit' in ctor of test object",
self != NULL);
92 self->waitpid_(pid, &status);
94 self->ensure_child_exit_(status, exit_status);
98 void ensure_child_signal(pid_t pid,
int signal = SIGTERM)
101 ensure(
"trying to call 'ensure_child_signal' in ctor of test object",
self != NULL);
104 self->waitpid_(pid, &status);
106 self->ensure_child_signal_(status, signal);
109 std::set<pid_t> get_pids()
const
114 ensure(
"trying to call 'get_pids' in ctor of test object",
self != NULL);
116 return self->get_pids_();
125 class test_object_posix
128 typedef std::map<pid_t, int> pid_map;
140 virtual ~test_object_posix()
151 std::ostringstream ss;
154 for(std::map<pid_t, int>::iterator i = pids_.begin(); i != pids_.end(); ++i)
157 kill_child_(i->first);
158 }
catch(
const rethrown &ex) {
159 ss << std::endl <<
"child " << ex.tr.pid <<
" has thrown an exception: " << ex.what();
160 }
catch(
const failure &ex) {
161 ss << std::endl << ex.what();
165 if(!ss.str().empty())
167 fail(ss.str().c_str());
174 friend class tut_posix;
176 friend class test_group_posix;
178 int get_pipe_()
const
188 ensure_errno(
"pipe() failed", ::pipe(fds) == 0);
190 pid_t pid = ::fork();
192 ensure_errno(
"fork() failed", pid >= 0);
197 ensure(
"duplicated child", pids_.insert( std::make_pair(pid, fds[0]) ).second);
215 void kill_child_(pid_t pid)
219 if(waitpid_(pid, &status, WNOHANG) == pid)
221 ensure_child_exit_(status, 0);
225 if(::kill(pid, SIGTERM) != 0)
235 std::ostringstream ss;
237 ss <<
"child " << pid <<
" could not be killed with SIGTERM, " << strerror_r(errno, e,
sizeof(e)) << std::endl;
242 if(waitpid_(pid, &status, WNOHANG) == pid)
245 ensure_child_signal_(status, SIGTERM);
247 ensure_equals(
"child process exists after SIGTERM", ::kill(pid, 0), -1);
254 if(waitpid_(pid, &status, WNOHANG) != pid)
257 if(::kill(pid, SIGKILL) != 0)
266 std::ostringstream ss;
268 ss <<
"child " << pid <<
" could not be killed with SIGKILL, " << strerror_r(errno, e,
sizeof(e)) << std::endl;
273 ensure_equals(
"wait after SIGKILL", waitpid_(pid, &status), pid);
274 ensure_child_signal_(status, SIGKILL);
276 ensure_equals(
"child process exists after SIGKILL", ::kill(pid, 0), -1);
278 std::ostringstream ss;
279 ss <<
"child " << pid <<
" had to be killed with SIGKILL";
284 test_result receive_result_(std::istream &ss, pid_t pid)
291 ss.ignore(1024,
'\n');
293 std::getline(ss, tr.group);
295 ss.ignore(1024,
'\n');
296 std::getline(ss, tr.name);
297 std::getline(ss, tr.exception_typeid);
298 std::copy( std::istreambuf_iterator<char>(ss.rdbuf()),
299 std::istreambuf_iterator<char>(),
300 std::back_inserter(tr.message) );
309 fdclose(
int fd): fd_(fd) { }
318 pid_t waitpid_(pid_t pid,
int *status,
int flags = 0)
321 ensure(
"trying to wait for unknown pid", pids_.count(pid) > 0);
323 pid_t p = ::waitpid(pid, status, flags);
324 if( (flags & WNOHANG) && (p != pid) )
337 int pipe = pids_[pid];
340 FD_SET(pipe, &fdset);
342 int result = select(pipe+1, &fdset, NULL, NULL, &tv);
343 ensure_errno(
"sanity check on select() failed", result >= 0);
347 ensure(
"sanity check on FD_ISSET() failed", FD_ISSET(pipe, &fdset) );
349 std::stringstream ss;
353 int r = read(pipe, buffer,
sizeof(buffer));
354 ensure_errno(
"sanity check on read() failed", r >= 0);
359 throw rethrown( receive_result_(ss, pid) );
366 void ensure_child_exit_(
int status,
int exit_status)
368 if(WIFSIGNALED(status))
370 std::ostringstream ss;
371 ss <<
"child killed by signal " << WTERMSIG(status)
372 <<
": expected exit with code " << exit_status;
374 throw failure(ss.str().c_str());
377 if(WIFEXITED(status))
379 if(WEXITSTATUS(status) != exit_status)
381 std::ostringstream ss;
382 ss <<
"child exited, expected '"
385 << WEXITSTATUS(status)
388 throw failure(ss.str().c_str());
392 if(WIFSTOPPED(status))
394 std::ostringstream ss;
395 ss <<
"child stopped by signal " << WTERMSIG(status)
396 <<
": expected exit with code " << exit_status;
397 throw failure(ss.str().c_str());
401 void ensure_child_signal_(
int status,
int signal)
403 if(WIFSIGNALED(status))
405 if(WTERMSIG(status) != signal)
407 std::ostringstream ss;
408 ss <<
"child killed by signal, expected '"
413 throw failure(ss.str().c_str());
417 if(WIFEXITED(status))
419 std::ostringstream ss;
420 ss <<
"child exited with code " << WEXITSTATUS(status)
421 <<
": expected signal " << signal;
423 throw failure(ss.str().c_str());
426 if(WIFSTOPPED(status))
428 std::ostringstream ss;
429 ss <<
"child stopped by signal " << WTERMSIG(status)
430 <<
": expected kill by signal " << signal;
432 throw failure(ss.str().c_str());
436 std::set<pid_t> get_pids_()
const
441 for(pid_map::const_iterator i = pids_.begin(); i != pids_.end(); ++i)
443 pids.insert( i->first );
Definition: tut_posix.hpp:460
Definition: tut_posix.hpp:467
void clear_callbacks()
Definition: tut_runner.hpp:182
test finished successfully
Definition: tut_result.hpp:91
result_type
Definition: tut_result.hpp:89
Definition: tut_result.hpp:69