1*11be35a1SLionel Sambuc // Copyright 2010 Google Inc.
2*11be35a1SLionel Sambuc // All rights reserved.
3*11be35a1SLionel Sambuc //
4*11be35a1SLionel Sambuc // Redistribution and use in source and binary forms, with or without
5*11be35a1SLionel Sambuc // modification, are permitted provided that the following conditions are
6*11be35a1SLionel Sambuc // met:
7*11be35a1SLionel Sambuc //
8*11be35a1SLionel Sambuc // * Redistributions of source code must retain the above copyright
9*11be35a1SLionel Sambuc // notice, this list of conditions and the following disclaimer.
10*11be35a1SLionel Sambuc // * Redistributions in binary form must reproduce the above copyright
11*11be35a1SLionel Sambuc // notice, this list of conditions and the following disclaimer in the
12*11be35a1SLionel Sambuc // documentation and/or other materials provided with the distribution.
13*11be35a1SLionel Sambuc // * Neither the name of Google Inc. nor the names of its contributors
14*11be35a1SLionel Sambuc // may be used to endorse or promote products derived from this software
15*11be35a1SLionel Sambuc // without specific prior written permission.
16*11be35a1SLionel Sambuc //
17*11be35a1SLionel Sambuc // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
18*11be35a1SLionel Sambuc // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
19*11be35a1SLionel Sambuc // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
20*11be35a1SLionel Sambuc // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
21*11be35a1SLionel Sambuc // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
22*11be35a1SLionel Sambuc // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
23*11be35a1SLionel Sambuc // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
24*11be35a1SLionel Sambuc // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
25*11be35a1SLionel Sambuc // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
26*11be35a1SLionel Sambuc // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
27*11be35a1SLionel Sambuc // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
28*11be35a1SLionel Sambuc
29*11be35a1SLionel Sambuc #include "utils/process/child.ipp"
30*11be35a1SLionel Sambuc
31*11be35a1SLionel Sambuc extern "C" {
32*11be35a1SLionel Sambuc #include <sys/stat.h>
33*11be35a1SLionel Sambuc #include <sys/wait.h>
34*11be35a1SLionel Sambuc
35*11be35a1SLionel Sambuc #include <fcntl.h>
36*11be35a1SLionel Sambuc #include <signal.h>
37*11be35a1SLionel Sambuc #include <unistd.h>
38*11be35a1SLionel Sambuc }
39*11be35a1SLionel Sambuc
40*11be35a1SLionel Sambuc #include <cstdarg>
41*11be35a1SLionel Sambuc #include <cerrno>
42*11be35a1SLionel Sambuc #include <cstdlib>
43*11be35a1SLionel Sambuc #include <cstring>
44*11be35a1SLionel Sambuc #include <fstream>
45*11be35a1SLionel Sambuc #include <iostream>
46*11be35a1SLionel Sambuc
47*11be35a1SLionel Sambuc #include <atf-c++.hpp>
48*11be35a1SLionel Sambuc
49*11be35a1SLionel Sambuc #include "utils/defs.hpp"
50*11be35a1SLionel Sambuc #include "utils/env.hpp"
51*11be35a1SLionel Sambuc #include "utils/format/macros.hpp"
52*11be35a1SLionel Sambuc #include "utils/fs/operations.hpp"
53*11be35a1SLionel Sambuc #include "utils/logging/macros.hpp"
54*11be35a1SLionel Sambuc #include "utils/process/exceptions.hpp"
55*11be35a1SLionel Sambuc #include "utils/process/system.hpp"
56*11be35a1SLionel Sambuc #include "utils/sanity.hpp"
57*11be35a1SLionel Sambuc
58*11be35a1SLionel Sambuc namespace fs = utils::fs;
59*11be35a1SLionel Sambuc namespace logging = utils::logging;
60*11be35a1SLionel Sambuc namespace process = utils::process;
61*11be35a1SLionel Sambuc
62*11be35a1SLionel Sambuc
63*11be35a1SLionel Sambuc namespace {
64*11be35a1SLionel Sambuc
65*11be35a1SLionel Sambuc
66*11be35a1SLionel Sambuc /// Body for a process that prints a simple message and exits.
67*11be35a1SLionel Sambuc ///
68*11be35a1SLionel Sambuc /// \tparam ExitStatus The exit status for the subprocess.
69*11be35a1SLionel Sambuc /// \tparam Message A single character that will be prepended to the printed
70*11be35a1SLionel Sambuc /// messages. This would ideally be a string, but we cannot templatize a
71*11be35a1SLionel Sambuc /// function with an object nor a pointer.
72*11be35a1SLionel Sambuc template< int ExitStatus, char Message >
73*11be35a1SLionel Sambuc static void
child_simple_function(void)74*11be35a1SLionel Sambuc child_simple_function(void)
75*11be35a1SLionel Sambuc {
76*11be35a1SLionel Sambuc std::cout << "To stdout: " << Message << "\n";
77*11be35a1SLionel Sambuc std::cerr << "To stderr: " << Message << "\n";
78*11be35a1SLionel Sambuc std::exit(ExitStatus);
79*11be35a1SLionel Sambuc }
80*11be35a1SLionel Sambuc
81*11be35a1SLionel Sambuc
82*11be35a1SLionel Sambuc /// Functor for the body of a process that prints a simple message and exits.
83*11be35a1SLionel Sambuc class child_simple_functor {
84*11be35a1SLionel Sambuc /// The exit status that the subprocess will yield.
85*11be35a1SLionel Sambuc int _exitstatus;
86*11be35a1SLionel Sambuc
87*11be35a1SLionel Sambuc /// The message to print on stdout and stderr.
88*11be35a1SLionel Sambuc std::string _message;
89*11be35a1SLionel Sambuc
90*11be35a1SLionel Sambuc public:
91*11be35a1SLionel Sambuc /// Constructs a new functor.
92*11be35a1SLionel Sambuc ///
93*11be35a1SLionel Sambuc /// \param exitstatus The exit status that the subprocess will yield.
94*11be35a1SLionel Sambuc /// \param message The message to print on stdout and stderr.
child_simple_functor(const int exitstatus,const std::string & message)95*11be35a1SLionel Sambuc child_simple_functor(const int exitstatus, const std::string& message) :
96*11be35a1SLionel Sambuc _exitstatus(exitstatus),
97*11be35a1SLionel Sambuc _message(message)
98*11be35a1SLionel Sambuc {
99*11be35a1SLionel Sambuc }
100*11be35a1SLionel Sambuc
101*11be35a1SLionel Sambuc /// Body for the subprocess.
102*11be35a1SLionel Sambuc void
operator ()(void)103*11be35a1SLionel Sambuc operator()(void)
104*11be35a1SLionel Sambuc {
105*11be35a1SLionel Sambuc std::cout << "To stdout: " << _message << "\n";
106*11be35a1SLionel Sambuc std::cerr << "To stderr: " << _message << "\n";
107*11be35a1SLionel Sambuc std::exit(_exitstatus);
108*11be35a1SLionel Sambuc }
109*11be35a1SLionel Sambuc };
110*11be35a1SLionel Sambuc
111*11be35a1SLionel Sambuc
112*11be35a1SLionel Sambuc /// Body for a process that prints many messages to stdout and exits.
113*11be35a1SLionel Sambuc ///
114*11be35a1SLionel Sambuc /// The goal of this body is to validate that any buffering performed on the
115*11be35a1SLionel Sambuc /// parent process to read the output of the subprocess works correctly.
116*11be35a1SLionel Sambuc static void
child_printer_function(void)117*11be35a1SLionel Sambuc child_printer_function(void)
118*11be35a1SLionel Sambuc {
119*11be35a1SLionel Sambuc for (std::size_t i = 0; i < 100; i++)
120*11be35a1SLionel Sambuc std::cout << "This is a message to stdout, sequence " << i << "\n";
121*11be35a1SLionel Sambuc std::cout.flush();
122*11be35a1SLionel Sambuc std::cerr << "Exiting\n";
123*11be35a1SLionel Sambuc std::exit(EXIT_SUCCESS);
124*11be35a1SLionel Sambuc }
125*11be35a1SLionel Sambuc
126*11be35a1SLionel Sambuc
127*11be35a1SLionel Sambuc /// Functor for the body of a process that runs child_printer_function.
128*11be35a1SLionel Sambuc class child_printer_functor {
129*11be35a1SLionel Sambuc public:
130*11be35a1SLionel Sambuc /// Body for the subprocess.
131*11be35a1SLionel Sambuc void
operator ()(void)132*11be35a1SLionel Sambuc operator()(void)
133*11be35a1SLionel Sambuc {
134*11be35a1SLionel Sambuc child_printer_function();
135*11be35a1SLionel Sambuc }
136*11be35a1SLionel Sambuc };
137*11be35a1SLionel Sambuc
138*11be35a1SLionel Sambuc
139*11be35a1SLionel Sambuc /// Body for a child process that creates a pidfile.
140*11be35a1SLionel Sambuc static void
child_write_pid(void)141*11be35a1SLionel Sambuc child_write_pid(void)
142*11be35a1SLionel Sambuc {
143*11be35a1SLionel Sambuc std::ofstream output("pidfile");
144*11be35a1SLionel Sambuc output << ::getpid() << "\n";
145*11be35a1SLionel Sambuc output.close();
146*11be35a1SLionel Sambuc std::exit(EXIT_SUCCESS);
147*11be35a1SLionel Sambuc }
148*11be35a1SLionel Sambuc
149*11be35a1SLionel Sambuc
150*11be35a1SLionel Sambuc /// A child process that returns.
151*11be35a1SLionel Sambuc ///
152*11be35a1SLionel Sambuc /// The fork() wrappers are supposed to capture this condition and terminate the
153*11be35a1SLionel Sambuc /// child before the code returns to the fork() call point.
154*11be35a1SLionel Sambuc static void
child_return(void)155*11be35a1SLionel Sambuc child_return(void)
156*11be35a1SLionel Sambuc {
157*11be35a1SLionel Sambuc }
158*11be35a1SLionel Sambuc
159*11be35a1SLionel Sambuc
160*11be35a1SLionel Sambuc /// A child process that raises an exception.
161*11be35a1SLionel Sambuc ///
162*11be35a1SLionel Sambuc /// The fork() wrappers are supposed to capture this condition and terminate the
163*11be35a1SLionel Sambuc /// child before the code returns to the fork() call point.
164*11be35a1SLionel Sambuc ///
165*11be35a1SLionel Sambuc /// \tparam Type The type of the exception to raise.
166*11be35a1SLionel Sambuc /// \tparam Value The value passed to the constructor of the exception type. In
167*11be35a1SLionel Sambuc /// general, this only makes sense if Type is a primitive type so that, in
168*11be35a1SLionel Sambuc /// the end, the code becomes "throw int(123)".
169*11be35a1SLionel Sambuc ///
170*11be35a1SLionel Sambuc /// \throw Type An exception of the provided type.
171*11be35a1SLionel Sambuc template< class Type, Type Value >
172*11be35a1SLionel Sambuc void
child_raise_exception(void)173*11be35a1SLionel Sambuc child_raise_exception(void)
174*11be35a1SLionel Sambuc {
175*11be35a1SLionel Sambuc throw Type(Value);
176*11be35a1SLionel Sambuc }
177*11be35a1SLionel Sambuc
178*11be35a1SLionel Sambuc
179*11be35a1SLionel Sambuc /// Calculates the path to the test helpers binary.
180*11be35a1SLionel Sambuc ///
181*11be35a1SLionel Sambuc /// \param tc A pointer to the caller test case, needed to extract the value of
182*11be35a1SLionel Sambuc /// the "srcdir" property.
183*11be35a1SLionel Sambuc ///
184*11be35a1SLionel Sambuc /// \return The path to the helpers binary.
185*11be35a1SLionel Sambuc static fs::path
get_helpers(const atf::tests::tc * tc)186*11be35a1SLionel Sambuc get_helpers(const atf::tests::tc* tc)
187*11be35a1SLionel Sambuc {
188*11be35a1SLionel Sambuc return fs::path(tc->get_config_var("srcdir")) / "helpers";
189*11be35a1SLionel Sambuc }
190*11be35a1SLionel Sambuc
191*11be35a1SLionel Sambuc
192*11be35a1SLionel Sambuc /// Mock fork(2) that just returns an error.
193*11be35a1SLionel Sambuc ///
194*11be35a1SLionel Sambuc /// \tparam Errno The value to set as the errno of the failed call.
195*11be35a1SLionel Sambuc ///
196*11be35a1SLionel Sambuc /// \return Always -1.
197*11be35a1SLionel Sambuc template< int Errno >
198*11be35a1SLionel Sambuc static pid_t
fork_fail(void)199*11be35a1SLionel Sambuc fork_fail(void) throw()
200*11be35a1SLionel Sambuc {
201*11be35a1SLionel Sambuc errno = Errno;
202*11be35a1SLionel Sambuc return -1;
203*11be35a1SLionel Sambuc }
204*11be35a1SLionel Sambuc
205*11be35a1SLionel Sambuc
206*11be35a1SLionel Sambuc /// Mock open(2) that fails if the 'raise-error' file is opened.
207*11be35a1SLionel Sambuc ///
208*11be35a1SLionel Sambuc /// \tparam Errno The value to set as the errno if the known failure triggers.
209*11be35a1SLionel Sambuc /// \param path The path to the file to be opened.
210*11be35a1SLionel Sambuc /// \param flags The open flags.
211*11be35a1SLionel Sambuc /// \param ... The file mode creation, if flags contains O_CREAT.
212*11be35a1SLionel Sambuc ///
213*11be35a1SLionel Sambuc /// \return The opened file handle or -1 on error.
214*11be35a1SLionel Sambuc template< int Errno >
215*11be35a1SLionel Sambuc static int
open_fail(const char * path,const int flags,...)216*11be35a1SLionel Sambuc open_fail(const char* path, const int flags, ...) throw()
217*11be35a1SLionel Sambuc {
218*11be35a1SLionel Sambuc if (std::strcmp(path, "raise-error") == 0) {
219*11be35a1SLionel Sambuc errno = Errno;
220*11be35a1SLionel Sambuc return -1;
221*11be35a1SLionel Sambuc } else {
222*11be35a1SLionel Sambuc va_list ap;
223*11be35a1SLionel Sambuc va_start(ap, flags);
224*11be35a1SLionel Sambuc const int mode = va_arg(ap, int);
225*11be35a1SLionel Sambuc va_end(ap);
226*11be35a1SLionel Sambuc return ::open(path, flags, mode);
227*11be35a1SLionel Sambuc }
228*11be35a1SLionel Sambuc }
229*11be35a1SLionel Sambuc
230*11be35a1SLionel Sambuc
231*11be35a1SLionel Sambuc /// Mock pipe(2) that just returns an error.
232*11be35a1SLionel Sambuc ///
233*11be35a1SLionel Sambuc /// \tparam Errno The value to set as the errno of the failed call.
234*11be35a1SLionel Sambuc /// \param [out] unused_fildes A pointer to a 2-integer array.
235*11be35a1SLionel Sambuc ///
236*11be35a1SLionel Sambuc /// \return Always -1.
237*11be35a1SLionel Sambuc template< int Errno >
238*11be35a1SLionel Sambuc static pid_t
pipe_fail(int * UTILS_UNUSED_PARAM (fildes))239*11be35a1SLionel Sambuc pipe_fail(int* UTILS_UNUSED_PARAM(fildes)) throw()
240*11be35a1SLionel Sambuc {
241*11be35a1SLionel Sambuc errno = Errno;
242*11be35a1SLionel Sambuc return -1;
243*11be35a1SLionel Sambuc }
244*11be35a1SLionel Sambuc
245*11be35a1SLionel Sambuc
246*11be35a1SLionel Sambuc /// Helper for child tests to validate inheritance of stdout/stderr.
247*11be35a1SLionel Sambuc ///
248*11be35a1SLionel Sambuc /// This function ensures that passing one of /dev/stdout or /dev/stderr to
249*11be35a1SLionel Sambuc /// the child__fork_files fork method does the right thing. The idea is that we
250*11be35a1SLionel Sambuc /// call fork with the given parameters and then make our child redirect one of
251*11be35a1SLionel Sambuc /// its file descriptors to a specific file without going through the process
252*11be35a1SLionel Sambuc /// library. We then validate if this redirection worked and got the expected
253*11be35a1SLionel Sambuc /// output.
254*11be35a1SLionel Sambuc ///
255*11be35a1SLionel Sambuc /// \param fork_stdout The path to pass to the fork call as the stdout file.
256*11be35a1SLionel Sambuc /// \param fork_stderr The path to pass to the fork call as the stderr file.
257*11be35a1SLionel Sambuc /// \param child_file The file to explicitly in the subchild.
258*11be35a1SLionel Sambuc /// \param child_fd The file descriptor to which to attach child_file.
259*11be35a1SLionel Sambuc static void
do_inherit_test(const char * fork_stdout,const char * fork_stderr,const char * child_file,const int child_fd)260*11be35a1SLionel Sambuc do_inherit_test(const char* fork_stdout, const char* fork_stderr,
261*11be35a1SLionel Sambuc const char* child_file, const int child_fd)
262*11be35a1SLionel Sambuc {
263*11be35a1SLionel Sambuc const pid_t pid = ::fork();
264*11be35a1SLionel Sambuc ATF_REQUIRE(pid != -1);
265*11be35a1SLionel Sambuc if (pid == 0) {
266*11be35a1SLionel Sambuc logging::set_inmemory();
267*11be35a1SLionel Sambuc
268*11be35a1SLionel Sambuc const int fd = ::open(child_file, O_CREAT | O_WRONLY | O_TRUNC, 0644);
269*11be35a1SLionel Sambuc if (fd != child_fd) {
270*11be35a1SLionel Sambuc if (::dup2(fd, child_fd) == -1)
271*11be35a1SLionel Sambuc std::abort();
272*11be35a1SLionel Sambuc ::close(fd);
273*11be35a1SLionel Sambuc }
274*11be35a1SLionel Sambuc
275*11be35a1SLionel Sambuc std::auto_ptr< process::child > child = process::child::fork_files(
276*11be35a1SLionel Sambuc child_simple_function< 123, 'Z' >,
277*11be35a1SLionel Sambuc fs::path(fork_stdout), fs::path(fork_stderr));
278*11be35a1SLionel Sambuc const process::status status = child->wait();
279*11be35a1SLionel Sambuc if (!status.exited() || status.exitstatus() != 123)
280*11be35a1SLionel Sambuc std::abort();
281*11be35a1SLionel Sambuc std::exit(EXIT_SUCCESS);
282*11be35a1SLionel Sambuc } else {
283*11be35a1SLionel Sambuc int status;
284*11be35a1SLionel Sambuc ATF_REQUIRE(::waitpid(pid, &status, 0) != -1);
285*11be35a1SLionel Sambuc ATF_REQUIRE(WIFEXITED(status));
286*11be35a1SLionel Sambuc ATF_REQUIRE_EQ(EXIT_SUCCESS, WEXITSTATUS(status));
287*11be35a1SLionel Sambuc ATF_REQUIRE(atf::utils::grep_file("stdout: Z", "stdout.txt"));
288*11be35a1SLionel Sambuc ATF_REQUIRE(atf::utils::grep_file("stderr: Z", "stderr.txt"));
289*11be35a1SLionel Sambuc }
290*11be35a1SLionel Sambuc }
291*11be35a1SLionel Sambuc
292*11be35a1SLionel Sambuc
293*11be35a1SLionel Sambuc /// Performs a "child__fork_capture__ok_*" test.
294*11be35a1SLionel Sambuc ///
295*11be35a1SLionel Sambuc /// This test basically ensures that the child__fork_capture class spawns a
296*11be35a1SLionel Sambuc /// process whose output is captured in an input stream.
297*11be35a1SLionel Sambuc ///
298*11be35a1SLionel Sambuc /// \tparam Hook The type of the fork hook to use.
299*11be35a1SLionel Sambuc /// \param hook The hook to the fork call.
300*11be35a1SLionel Sambuc template< class Hook >
301*11be35a1SLionel Sambuc static void
child__fork_capture__ok(Hook hook)302*11be35a1SLionel Sambuc child__fork_capture__ok(Hook hook)
303*11be35a1SLionel Sambuc {
304*11be35a1SLionel Sambuc std::cout << "This unflushed message should not propagate to the child";
305*11be35a1SLionel Sambuc std::cerr << "This unflushed message should not propagate to the child";
306*11be35a1SLionel Sambuc std::auto_ptr< process::child > child = process::child::fork_capture(hook);
307*11be35a1SLionel Sambuc std::cout << std::endl;
308*11be35a1SLionel Sambuc std::cerr << std::endl;
309*11be35a1SLionel Sambuc
310*11be35a1SLionel Sambuc std::istream& output = child->output();
311*11be35a1SLionel Sambuc for (std::size_t i = 0; i < 100; i++) {
312*11be35a1SLionel Sambuc std::string line;
313*11be35a1SLionel Sambuc ATF_REQUIRE(std::getline(output, line).good());
314*11be35a1SLionel Sambuc ATF_REQUIRE_EQ((F("This is a message to stdout, "
315*11be35a1SLionel Sambuc "sequence %s") % i).str(), line);
316*11be35a1SLionel Sambuc }
317*11be35a1SLionel Sambuc
318*11be35a1SLionel Sambuc std::string line;
319*11be35a1SLionel Sambuc ATF_REQUIRE(std::getline(output, line).good());
320*11be35a1SLionel Sambuc ATF_REQUIRE_EQ("Exiting", line);
321*11be35a1SLionel Sambuc
322*11be35a1SLionel Sambuc process::status status = child->wait();
323*11be35a1SLionel Sambuc ATF_REQUIRE(status.exited());
324*11be35a1SLionel Sambuc ATF_REQUIRE_EQ(EXIT_SUCCESS, status.exitstatus());
325*11be35a1SLionel Sambuc }
326*11be35a1SLionel Sambuc
327*11be35a1SLionel Sambuc
328*11be35a1SLionel Sambuc } // anonymous namespace
329*11be35a1SLionel Sambuc
330*11be35a1SLionel Sambuc
331*11be35a1SLionel Sambuc ATF_TEST_CASE_WITHOUT_HEAD(child__fork_capture__ok_function);
ATF_TEST_CASE_BODY(child__fork_capture__ok_function)332*11be35a1SLionel Sambuc ATF_TEST_CASE_BODY(child__fork_capture__ok_function)
333*11be35a1SLionel Sambuc {
334*11be35a1SLionel Sambuc child__fork_capture__ok(child_printer_function);
335*11be35a1SLionel Sambuc }
336*11be35a1SLionel Sambuc
337*11be35a1SLionel Sambuc
338*11be35a1SLionel Sambuc ATF_TEST_CASE_WITHOUT_HEAD(child__fork_capture__ok_functor);
ATF_TEST_CASE_BODY(child__fork_capture__ok_functor)339*11be35a1SLionel Sambuc ATF_TEST_CASE_BODY(child__fork_capture__ok_functor)
340*11be35a1SLionel Sambuc {
341*11be35a1SLionel Sambuc child__fork_capture__ok(child_printer_functor());
342*11be35a1SLionel Sambuc }
343*11be35a1SLionel Sambuc
344*11be35a1SLionel Sambuc
345*11be35a1SLionel Sambuc ATF_TEST_CASE_WITHOUT_HEAD(child__fork_capture__pipe_fail);
ATF_TEST_CASE_BODY(child__fork_capture__pipe_fail)346*11be35a1SLionel Sambuc ATF_TEST_CASE_BODY(child__fork_capture__pipe_fail)
347*11be35a1SLionel Sambuc {
348*11be35a1SLionel Sambuc process::detail::syscall_pipe = pipe_fail< 23 >;
349*11be35a1SLionel Sambuc try {
350*11be35a1SLionel Sambuc process::child::fork_capture(child_simple_function< 1, 'A' >);
351*11be35a1SLionel Sambuc fail("Expected exception but none raised");
352*11be35a1SLionel Sambuc } catch (const process::system_error& e) {
353*11be35a1SLionel Sambuc ATF_REQUIRE(atf::utils::grep_string("pipe.*failed", e.what()));
354*11be35a1SLionel Sambuc ATF_REQUIRE_EQ(23, e.original_errno());
355*11be35a1SLionel Sambuc }
356*11be35a1SLionel Sambuc }
357*11be35a1SLionel Sambuc
358*11be35a1SLionel Sambuc
359*11be35a1SLionel Sambuc ATF_TEST_CASE_WITHOUT_HEAD(child__fork_capture__fork_cannot_exit);
ATF_TEST_CASE_BODY(child__fork_capture__fork_cannot_exit)360*11be35a1SLionel Sambuc ATF_TEST_CASE_BODY(child__fork_capture__fork_cannot_exit)
361*11be35a1SLionel Sambuc {
362*11be35a1SLionel Sambuc const pid_t parent_pid = ::getpid();
363*11be35a1SLionel Sambuc atf::utils::create_file("to-not-be-deleted", "");
364*11be35a1SLionel Sambuc
365*11be35a1SLionel Sambuc std::auto_ptr< process::child > child = process::child::fork_capture(
366*11be35a1SLionel Sambuc child_return);
367*11be35a1SLionel Sambuc if (::getpid() != parent_pid) {
368*11be35a1SLionel Sambuc // If we enter this clause, it is because the hook returned.
369*11be35a1SLionel Sambuc ::unlink("to-not-be-deleted");
370*11be35a1SLionel Sambuc std::exit(EXIT_SUCCESS);
371*11be35a1SLionel Sambuc }
372*11be35a1SLionel Sambuc
373*11be35a1SLionel Sambuc const process::status status = child->wait();
374*11be35a1SLionel Sambuc ATF_REQUIRE(status.signaled());
375*11be35a1SLionel Sambuc ATF_REQUIRE(fs::exists(fs::path("to-not-be-deleted")));
376*11be35a1SLionel Sambuc }
377*11be35a1SLionel Sambuc
378*11be35a1SLionel Sambuc
379*11be35a1SLionel Sambuc ATF_TEST_CASE_WITHOUT_HEAD(child__fork_capture__fork_cannot_unwind);
ATF_TEST_CASE_BODY(child__fork_capture__fork_cannot_unwind)380*11be35a1SLionel Sambuc ATF_TEST_CASE_BODY(child__fork_capture__fork_cannot_unwind)
381*11be35a1SLionel Sambuc {
382*11be35a1SLionel Sambuc const pid_t parent_pid = ::getpid();
383*11be35a1SLionel Sambuc atf::utils::create_file("to-not-be-deleted", "");
384*11be35a1SLionel Sambuc try {
385*11be35a1SLionel Sambuc std::auto_ptr< process::child > child = process::child::fork_capture(
386*11be35a1SLionel Sambuc child_raise_exception< int, 123 >);
387*11be35a1SLionel Sambuc const process::status status = child->wait();
388*11be35a1SLionel Sambuc ATF_REQUIRE(status.signaled());
389*11be35a1SLionel Sambuc ATF_REQUIRE(fs::exists(fs::path("to-not-be-deleted")));
390*11be35a1SLionel Sambuc } catch (const int i) {
391*11be35a1SLionel Sambuc // If we enter this clause, it is because an exception leaked from the
392*11be35a1SLionel Sambuc // hook.
393*11be35a1SLionel Sambuc INV(parent_pid != ::getpid());
394*11be35a1SLionel Sambuc INV(i == 123);
395*11be35a1SLionel Sambuc ::unlink("to-not-be-deleted");
396*11be35a1SLionel Sambuc std::exit(EXIT_SUCCESS);
397*11be35a1SLionel Sambuc }
398*11be35a1SLionel Sambuc }
399*11be35a1SLionel Sambuc
400*11be35a1SLionel Sambuc
401*11be35a1SLionel Sambuc ATF_TEST_CASE_WITHOUT_HEAD(child__fork_capture__fork_fail);
ATF_TEST_CASE_BODY(child__fork_capture__fork_fail)402*11be35a1SLionel Sambuc ATF_TEST_CASE_BODY(child__fork_capture__fork_fail)
403*11be35a1SLionel Sambuc {
404*11be35a1SLionel Sambuc process::detail::syscall_fork = fork_fail< 89 >;
405*11be35a1SLionel Sambuc try {
406*11be35a1SLionel Sambuc process::child::fork_capture(child_simple_function< 1, 'A' >);
407*11be35a1SLionel Sambuc fail("Expected exception but none raised");
408*11be35a1SLionel Sambuc } catch (const process::system_error& e) {
409*11be35a1SLionel Sambuc ATF_REQUIRE(atf::utils::grep_string("fork.*failed", e.what()));
410*11be35a1SLionel Sambuc ATF_REQUIRE_EQ(89, e.original_errno());
411*11be35a1SLionel Sambuc }
412*11be35a1SLionel Sambuc }
413*11be35a1SLionel Sambuc
414*11be35a1SLionel Sambuc
415*11be35a1SLionel Sambuc ATF_TEST_CASE_WITHOUT_HEAD(child__fork_files__ok_function);
ATF_TEST_CASE_BODY(child__fork_files__ok_function)416*11be35a1SLionel Sambuc ATF_TEST_CASE_BODY(child__fork_files__ok_function)
417*11be35a1SLionel Sambuc {
418*11be35a1SLionel Sambuc const fs::path file1("file1.txt");
419*11be35a1SLionel Sambuc const fs::path file2("file2.txt");
420*11be35a1SLionel Sambuc
421*11be35a1SLionel Sambuc std::auto_ptr< process::child > child = process::child::fork_files(
422*11be35a1SLionel Sambuc child_simple_function< 15, 'Z' >, file1, file2);
423*11be35a1SLionel Sambuc const process::status status = child->wait();
424*11be35a1SLionel Sambuc ATF_REQUIRE(status.exited());
425*11be35a1SLionel Sambuc ATF_REQUIRE_EQ(15, status.exitstatus());
426*11be35a1SLionel Sambuc
427*11be35a1SLionel Sambuc ATF_REQUIRE( atf::utils::grep_file("^To stdout: Z$", file1.str()));
428*11be35a1SLionel Sambuc ATF_REQUIRE(!atf::utils::grep_file("^To stdout: Z$", file2.str()));
429*11be35a1SLionel Sambuc
430*11be35a1SLionel Sambuc ATF_REQUIRE( atf::utils::grep_file("^To stderr: Z$", file2.str()));
431*11be35a1SLionel Sambuc ATF_REQUIRE(!atf::utils::grep_file("^To stderr: Z$", file1.str()));
432*11be35a1SLionel Sambuc }
433*11be35a1SLionel Sambuc
434*11be35a1SLionel Sambuc
435*11be35a1SLionel Sambuc ATF_TEST_CASE_WITHOUT_HEAD(child__fork_files__ok_functor);
ATF_TEST_CASE_BODY(child__fork_files__ok_functor)436*11be35a1SLionel Sambuc ATF_TEST_CASE_BODY(child__fork_files__ok_functor)
437*11be35a1SLionel Sambuc {
438*11be35a1SLionel Sambuc const fs::path filea("fileA.txt");
439*11be35a1SLionel Sambuc const fs::path fileb("fileB.txt");
440*11be35a1SLionel Sambuc
441*11be35a1SLionel Sambuc atf::utils::create_file(filea.str(), "Initial stdout\n");
442*11be35a1SLionel Sambuc atf::utils::create_file(fileb.str(), "Initial stderr\n");
443*11be35a1SLionel Sambuc
444*11be35a1SLionel Sambuc std::auto_ptr< process::child > child = process::child::fork_files(
445*11be35a1SLionel Sambuc child_simple_functor(16, "a functor"), filea, fileb);
446*11be35a1SLionel Sambuc const process::status status = child->wait();
447*11be35a1SLionel Sambuc ATF_REQUIRE(status.exited());
448*11be35a1SLionel Sambuc ATF_REQUIRE_EQ(16, status.exitstatus());
449*11be35a1SLionel Sambuc
450*11be35a1SLionel Sambuc ATF_REQUIRE( atf::utils::grep_file("^Initial stdout$", filea.str()));
451*11be35a1SLionel Sambuc ATF_REQUIRE(!atf::utils::grep_file("^Initial stdout$", fileb.str()));
452*11be35a1SLionel Sambuc
453*11be35a1SLionel Sambuc ATF_REQUIRE( atf::utils::grep_file("^To stdout: a functor$", filea.str()));
454*11be35a1SLionel Sambuc ATF_REQUIRE(!atf::utils::grep_file("^To stdout: a functor$", fileb.str()));
455*11be35a1SLionel Sambuc
456*11be35a1SLionel Sambuc ATF_REQUIRE( atf::utils::grep_file("^Initial stderr$", fileb.str()));
457*11be35a1SLionel Sambuc ATF_REQUIRE(!atf::utils::grep_file("^Initial stderr$", filea.str()));
458*11be35a1SLionel Sambuc
459*11be35a1SLionel Sambuc ATF_REQUIRE( atf::utils::grep_file("^To stderr: a functor$", fileb.str()));
460*11be35a1SLionel Sambuc ATF_REQUIRE(!atf::utils::grep_file("^To stderr: a functor$", filea.str()));
461*11be35a1SLionel Sambuc }
462*11be35a1SLionel Sambuc
463*11be35a1SLionel Sambuc
464*11be35a1SLionel Sambuc ATF_TEST_CASE_WITHOUT_HEAD(child__fork_files__inherit_stdout);
ATF_TEST_CASE_BODY(child__fork_files__inherit_stdout)465*11be35a1SLionel Sambuc ATF_TEST_CASE_BODY(child__fork_files__inherit_stdout)
466*11be35a1SLionel Sambuc {
467*11be35a1SLionel Sambuc do_inherit_test("/dev/stdout", "stderr.txt", "stdout.txt", STDOUT_FILENO);
468*11be35a1SLionel Sambuc }
469*11be35a1SLionel Sambuc
470*11be35a1SLionel Sambuc
471*11be35a1SLionel Sambuc ATF_TEST_CASE_WITHOUT_HEAD(child__fork_files__inherit_stderr);
ATF_TEST_CASE_BODY(child__fork_files__inherit_stderr)472*11be35a1SLionel Sambuc ATF_TEST_CASE_BODY(child__fork_files__inherit_stderr)
473*11be35a1SLionel Sambuc {
474*11be35a1SLionel Sambuc do_inherit_test("stdout.txt", "/dev/stderr", "stderr.txt", STDERR_FILENO);
475*11be35a1SLionel Sambuc }
476*11be35a1SLionel Sambuc
477*11be35a1SLionel Sambuc
478*11be35a1SLionel Sambuc ATF_TEST_CASE_WITHOUT_HEAD(child__fork_files__fork_cannot_exit);
ATF_TEST_CASE_BODY(child__fork_files__fork_cannot_exit)479*11be35a1SLionel Sambuc ATF_TEST_CASE_BODY(child__fork_files__fork_cannot_exit)
480*11be35a1SLionel Sambuc {
481*11be35a1SLionel Sambuc const pid_t parent_pid = ::getpid();
482*11be35a1SLionel Sambuc atf::utils::create_file("to-not-be-deleted", "");
483*11be35a1SLionel Sambuc
484*11be35a1SLionel Sambuc std::auto_ptr< process::child > child = process::child::fork_files(
485*11be35a1SLionel Sambuc child_return, fs::path("out"), fs::path("err"));
486*11be35a1SLionel Sambuc if (::getpid() != parent_pid) {
487*11be35a1SLionel Sambuc // If we enter this clause, it is because the hook returned.
488*11be35a1SLionel Sambuc ::unlink("to-not-be-deleted");
489*11be35a1SLionel Sambuc std::exit(EXIT_SUCCESS);
490*11be35a1SLionel Sambuc }
491*11be35a1SLionel Sambuc
492*11be35a1SLionel Sambuc const process::status status = child->wait();
493*11be35a1SLionel Sambuc ATF_REQUIRE(status.signaled());
494*11be35a1SLionel Sambuc ATF_REQUIRE(fs::exists(fs::path("to-not-be-deleted")));
495*11be35a1SLionel Sambuc }
496*11be35a1SLionel Sambuc
497*11be35a1SLionel Sambuc
498*11be35a1SLionel Sambuc ATF_TEST_CASE_WITHOUT_HEAD(child__fork_files__fork_cannot_unwind);
ATF_TEST_CASE_BODY(child__fork_files__fork_cannot_unwind)499*11be35a1SLionel Sambuc ATF_TEST_CASE_BODY(child__fork_files__fork_cannot_unwind)
500*11be35a1SLionel Sambuc {
501*11be35a1SLionel Sambuc const pid_t parent_pid = ::getpid();
502*11be35a1SLionel Sambuc atf::utils::create_file("to-not-be-deleted", "");
503*11be35a1SLionel Sambuc try {
504*11be35a1SLionel Sambuc std::auto_ptr< process::child > child = process::child::fork_files(
505*11be35a1SLionel Sambuc child_raise_exception< int, 123 >, fs::path("out"),
506*11be35a1SLionel Sambuc fs::path("err"));
507*11be35a1SLionel Sambuc const process::status status = child->wait();
508*11be35a1SLionel Sambuc ATF_REQUIRE(status.signaled());
509*11be35a1SLionel Sambuc ATF_REQUIRE(fs::exists(fs::path("to-not-be-deleted")));
510*11be35a1SLionel Sambuc } catch (const int i) {
511*11be35a1SLionel Sambuc // If we enter this clause, it is because an exception leaked from the
512*11be35a1SLionel Sambuc // hook.
513*11be35a1SLionel Sambuc INV(parent_pid != ::getpid());
514*11be35a1SLionel Sambuc INV(i == 123);
515*11be35a1SLionel Sambuc ::unlink("to-not-be-deleted");
516*11be35a1SLionel Sambuc std::exit(EXIT_SUCCESS);
517*11be35a1SLionel Sambuc }
518*11be35a1SLionel Sambuc }
519*11be35a1SLionel Sambuc
520*11be35a1SLionel Sambuc
521*11be35a1SLionel Sambuc ATF_TEST_CASE_WITHOUT_HEAD(child__fork_files__fork_fail);
ATF_TEST_CASE_BODY(child__fork_files__fork_fail)522*11be35a1SLionel Sambuc ATF_TEST_CASE_BODY(child__fork_files__fork_fail)
523*11be35a1SLionel Sambuc {
524*11be35a1SLionel Sambuc process::detail::syscall_fork = fork_fail< 1234 >;
525*11be35a1SLionel Sambuc try {
526*11be35a1SLionel Sambuc process::child::fork_files(child_simple_function< 1, 'A' >,
527*11be35a1SLionel Sambuc fs::path("a.txt"), fs::path("b.txt"));
528*11be35a1SLionel Sambuc fail("Expected exception but none raised");
529*11be35a1SLionel Sambuc } catch (const process::system_error& e) {
530*11be35a1SLionel Sambuc ATF_REQUIRE(atf::utils::grep_string("fork.*failed", e.what()));
531*11be35a1SLionel Sambuc ATF_REQUIRE_EQ(1234, e.original_errno());
532*11be35a1SLionel Sambuc }
533*11be35a1SLionel Sambuc ATF_REQUIRE(!fs::exists(fs::path("a.txt")));
534*11be35a1SLionel Sambuc ATF_REQUIRE(!fs::exists(fs::path("b.txt")));
535*11be35a1SLionel Sambuc }
536*11be35a1SLionel Sambuc
537*11be35a1SLionel Sambuc
538*11be35a1SLionel Sambuc ATF_TEST_CASE_WITHOUT_HEAD(child__fork_files__create_stdout_fail);
ATF_TEST_CASE_BODY(child__fork_files__create_stdout_fail)539*11be35a1SLionel Sambuc ATF_TEST_CASE_BODY(child__fork_files__create_stdout_fail)
540*11be35a1SLionel Sambuc {
541*11be35a1SLionel Sambuc process::detail::syscall_open = open_fail< ENOENT >;
542*11be35a1SLionel Sambuc std::auto_ptr< process::child > child = process::child::fork_files(
543*11be35a1SLionel Sambuc child_simple_function< 1, 'A' >, fs::path("raise-error"),
544*11be35a1SLionel Sambuc fs::path("created"));
545*11be35a1SLionel Sambuc const process::status status = child->wait();
546*11be35a1SLionel Sambuc ATF_REQUIRE(status.signaled());
547*11be35a1SLionel Sambuc ATF_REQUIRE_EQ(SIGABRT, status.termsig());
548*11be35a1SLionel Sambuc ATF_REQUIRE(!fs::exists(fs::path("raise-error")));
549*11be35a1SLionel Sambuc ATF_REQUIRE(!fs::exists(fs::path("created")));
550*11be35a1SLionel Sambuc }
551*11be35a1SLionel Sambuc
552*11be35a1SLionel Sambuc
553*11be35a1SLionel Sambuc ATF_TEST_CASE_WITHOUT_HEAD(child__fork_files__create_stderr_fail);
ATF_TEST_CASE_BODY(child__fork_files__create_stderr_fail)554*11be35a1SLionel Sambuc ATF_TEST_CASE_BODY(child__fork_files__create_stderr_fail)
555*11be35a1SLionel Sambuc {
556*11be35a1SLionel Sambuc process::detail::syscall_open = open_fail< ENOENT >;
557*11be35a1SLionel Sambuc std::auto_ptr< process::child > child = process::child::fork_files(
558*11be35a1SLionel Sambuc child_simple_function< 1, 'A' >, fs::path("created"),
559*11be35a1SLionel Sambuc fs::path("raise-error"));
560*11be35a1SLionel Sambuc const process::status status = child->wait();
561*11be35a1SLionel Sambuc ATF_REQUIRE(status.signaled());
562*11be35a1SLionel Sambuc ATF_REQUIRE_EQ(SIGABRT, status.termsig());
563*11be35a1SLionel Sambuc ATF_REQUIRE(fs::exists(fs::path("created")));
564*11be35a1SLionel Sambuc ATF_REQUIRE(!fs::exists(fs::path("raise-error")));
565*11be35a1SLionel Sambuc }
566*11be35a1SLionel Sambuc
567*11be35a1SLionel Sambuc
568*11be35a1SLionel Sambuc ATF_TEST_CASE_WITHOUT_HEAD(child__spawn__absolute_path);
ATF_TEST_CASE_BODY(child__spawn__absolute_path)569*11be35a1SLionel Sambuc ATF_TEST_CASE_BODY(child__spawn__absolute_path)
570*11be35a1SLionel Sambuc {
571*11be35a1SLionel Sambuc std::vector< std::string > args;
572*11be35a1SLionel Sambuc args.push_back("return-code");
573*11be35a1SLionel Sambuc args.push_back("12");
574*11be35a1SLionel Sambuc
575*11be35a1SLionel Sambuc const fs::path program = get_helpers(this);
576*11be35a1SLionel Sambuc INV(program.is_absolute());
577*11be35a1SLionel Sambuc std::auto_ptr< process::child > child = process::child::spawn_files(
578*11be35a1SLionel Sambuc program, args, fs::path("out"), fs::path("err"));
579*11be35a1SLionel Sambuc
580*11be35a1SLionel Sambuc const process::status status = child->wait();
581*11be35a1SLionel Sambuc ATF_REQUIRE(status.exited());
582*11be35a1SLionel Sambuc ATF_REQUIRE_EQ(12, status.exitstatus());
583*11be35a1SLionel Sambuc }
584*11be35a1SLionel Sambuc
585*11be35a1SLionel Sambuc
586*11be35a1SLionel Sambuc ATF_TEST_CASE_WITHOUT_HEAD(child__spawn__relative_path);
ATF_TEST_CASE_BODY(child__spawn__relative_path)587*11be35a1SLionel Sambuc ATF_TEST_CASE_BODY(child__spawn__relative_path)
588*11be35a1SLionel Sambuc {
589*11be35a1SLionel Sambuc std::vector< std::string > args;
590*11be35a1SLionel Sambuc args.push_back("return-code");
591*11be35a1SLionel Sambuc args.push_back("13");
592*11be35a1SLionel Sambuc
593*11be35a1SLionel Sambuc ATF_REQUIRE(::mkdir("root", 0755) != -1);
594*11be35a1SLionel Sambuc ATF_REQUIRE(::symlink(get_helpers(this).c_str(), "root/helpers") != -1);
595*11be35a1SLionel Sambuc
596*11be35a1SLionel Sambuc std::auto_ptr< process::child > child = process::child::spawn_files(
597*11be35a1SLionel Sambuc fs::path("root/helpers"), args, fs::path("out"), fs::path("err"));
598*11be35a1SLionel Sambuc
599*11be35a1SLionel Sambuc const process::status status = child->wait();
600*11be35a1SLionel Sambuc ATF_REQUIRE(status.exited());
601*11be35a1SLionel Sambuc ATF_REQUIRE_EQ(13, status.exitstatus());
602*11be35a1SLionel Sambuc }
603*11be35a1SLionel Sambuc
604*11be35a1SLionel Sambuc
605*11be35a1SLionel Sambuc ATF_TEST_CASE_WITHOUT_HEAD(child__spawn__basename_only);
ATF_TEST_CASE_BODY(child__spawn__basename_only)606*11be35a1SLionel Sambuc ATF_TEST_CASE_BODY(child__spawn__basename_only)
607*11be35a1SLionel Sambuc {
608*11be35a1SLionel Sambuc std::vector< std::string > args;
609*11be35a1SLionel Sambuc args.push_back("return-code");
610*11be35a1SLionel Sambuc args.push_back("14");
611*11be35a1SLionel Sambuc
612*11be35a1SLionel Sambuc ATF_REQUIRE(::symlink(get_helpers(this).c_str(), "helpers") != -1);
613*11be35a1SLionel Sambuc
614*11be35a1SLionel Sambuc std::auto_ptr< process::child > child = process::child::spawn_files(
615*11be35a1SLionel Sambuc fs::path("helpers"), args, fs::path("out"), fs::path("err"));
616*11be35a1SLionel Sambuc
617*11be35a1SLionel Sambuc const process::status status = child->wait();
618*11be35a1SLionel Sambuc ATF_REQUIRE(status.exited());
619*11be35a1SLionel Sambuc ATF_REQUIRE_EQ(14, status.exitstatus());
620*11be35a1SLionel Sambuc }
621*11be35a1SLionel Sambuc
622*11be35a1SLionel Sambuc
623*11be35a1SLionel Sambuc ATF_TEST_CASE_WITHOUT_HEAD(child__spawn__no_path);
ATF_TEST_CASE_BODY(child__spawn__no_path)624*11be35a1SLionel Sambuc ATF_TEST_CASE_BODY(child__spawn__no_path)
625*11be35a1SLionel Sambuc {
626*11be35a1SLionel Sambuc logging::set_inmemory();
627*11be35a1SLionel Sambuc
628*11be35a1SLionel Sambuc std::vector< std::string > args;
629*11be35a1SLionel Sambuc args.push_back("return-code");
630*11be35a1SLionel Sambuc args.push_back("14");
631*11be35a1SLionel Sambuc
632*11be35a1SLionel Sambuc const fs::path helpers = get_helpers(this);
633*11be35a1SLionel Sambuc utils::setenv("PATH", helpers.branch_path().c_str());
634*11be35a1SLionel Sambuc std::auto_ptr< process::child > child = process::child::spawn_capture(
635*11be35a1SLionel Sambuc fs::path(helpers.leaf_name()), args);
636*11be35a1SLionel Sambuc
637*11be35a1SLionel Sambuc std::string line;
638*11be35a1SLionel Sambuc ATF_REQUIRE(std::getline(child->output(), line).good());
639*11be35a1SLionel Sambuc ATF_REQUIRE_MATCH("Failed to execute", line);
640*11be35a1SLionel Sambuc ATF_REQUIRE(!std::getline(child->output(), line));
641*11be35a1SLionel Sambuc
642*11be35a1SLionel Sambuc const process::status status = child->wait();
643*11be35a1SLionel Sambuc ATF_REQUIRE(status.signaled());
644*11be35a1SLionel Sambuc ATF_REQUIRE_EQ(SIGABRT, status.termsig());
645*11be35a1SLionel Sambuc }
646*11be35a1SLionel Sambuc
647*11be35a1SLionel Sambuc
648*11be35a1SLionel Sambuc ATF_TEST_CASE_WITHOUT_HEAD(child__spawn__no_args);
ATF_TEST_CASE_BODY(child__spawn__no_args)649*11be35a1SLionel Sambuc ATF_TEST_CASE_BODY(child__spawn__no_args)
650*11be35a1SLionel Sambuc {
651*11be35a1SLionel Sambuc std::vector< std::string > args;
652*11be35a1SLionel Sambuc std::auto_ptr< process::child > child = process::child::spawn_capture(
653*11be35a1SLionel Sambuc get_helpers(this), args);
654*11be35a1SLionel Sambuc
655*11be35a1SLionel Sambuc std::string line;
656*11be35a1SLionel Sambuc ATF_REQUIRE(std::getline(child->output(), line).good());
657*11be35a1SLionel Sambuc ATF_REQUIRE_EQ("Must provide a helper name", line);
658*11be35a1SLionel Sambuc ATF_REQUIRE(!std::getline(child->output(), line));
659*11be35a1SLionel Sambuc
660*11be35a1SLionel Sambuc const process::status status = child->wait();
661*11be35a1SLionel Sambuc ATF_REQUIRE(status.exited());
662*11be35a1SLionel Sambuc ATF_REQUIRE_EQ(EXIT_FAILURE, status.exitstatus());
663*11be35a1SLionel Sambuc }
664*11be35a1SLionel Sambuc
665*11be35a1SLionel Sambuc
666*11be35a1SLionel Sambuc ATF_TEST_CASE_WITHOUT_HEAD(child__spawn__some_args);
ATF_TEST_CASE_BODY(child__spawn__some_args)667*11be35a1SLionel Sambuc ATF_TEST_CASE_BODY(child__spawn__some_args)
668*11be35a1SLionel Sambuc {
669*11be35a1SLionel Sambuc std::vector< std::string > args;
670*11be35a1SLionel Sambuc args.push_back("print-args");
671*11be35a1SLionel Sambuc args.push_back("foo");
672*11be35a1SLionel Sambuc args.push_back(" bar baz ");
673*11be35a1SLionel Sambuc std::auto_ptr< process::child > child = process::child::spawn_capture(
674*11be35a1SLionel Sambuc get_helpers(this), args);
675*11be35a1SLionel Sambuc
676*11be35a1SLionel Sambuc std::string line;
677*11be35a1SLionel Sambuc ATF_REQUIRE(std::getline(child->output(), line).good());
678*11be35a1SLionel Sambuc ATF_REQUIRE_EQ("argv[0] = " + get_helpers(this).str(), line);
679*11be35a1SLionel Sambuc ATF_REQUIRE(std::getline(child->output(), line).good());
680*11be35a1SLionel Sambuc ATF_REQUIRE_EQ("argv[1] = print-args", line);
681*11be35a1SLionel Sambuc ATF_REQUIRE(std::getline(child->output(), line));
682*11be35a1SLionel Sambuc ATF_REQUIRE_EQ("argv[2] = foo", line);
683*11be35a1SLionel Sambuc ATF_REQUIRE(std::getline(child->output(), line));
684*11be35a1SLionel Sambuc ATF_REQUIRE_EQ("argv[3] = bar baz ", line);
685*11be35a1SLionel Sambuc ATF_REQUIRE(std::getline(child->output(), line));
686*11be35a1SLionel Sambuc ATF_REQUIRE_EQ("argv[4] = NULL", line);
687*11be35a1SLionel Sambuc ATF_REQUIRE(!std::getline(child->output(), line));
688*11be35a1SLionel Sambuc
689*11be35a1SLionel Sambuc const process::status status = child->wait();
690*11be35a1SLionel Sambuc ATF_REQUIRE(status.exited());
691*11be35a1SLionel Sambuc ATF_REQUIRE_EQ(EXIT_SUCCESS, status.exitstatus());
692*11be35a1SLionel Sambuc }
693*11be35a1SLionel Sambuc
694*11be35a1SLionel Sambuc
695*11be35a1SLionel Sambuc ATF_TEST_CASE_WITHOUT_HEAD(child__spawn__missing_program);
ATF_TEST_CASE_BODY(child__spawn__missing_program)696*11be35a1SLionel Sambuc ATF_TEST_CASE_BODY(child__spawn__missing_program)
697*11be35a1SLionel Sambuc {
698*11be35a1SLionel Sambuc std::vector< std::string > args;
699*11be35a1SLionel Sambuc std::auto_ptr< process::child > child = process::child::spawn_capture(
700*11be35a1SLionel Sambuc fs::path("a/b/c"), args);
701*11be35a1SLionel Sambuc
702*11be35a1SLionel Sambuc std::string line;
703*11be35a1SLionel Sambuc ATF_REQUIRE(std::getline(child->output(), line).good());
704*11be35a1SLionel Sambuc const std::string exp = "Failed to execute a/b/c: ";
705*11be35a1SLionel Sambuc ATF_REQUIRE_EQ(exp, line.substr(0, exp.length()));
706*11be35a1SLionel Sambuc ATF_REQUIRE(!std::getline(child->output(), line));
707*11be35a1SLionel Sambuc
708*11be35a1SLionel Sambuc const process::status status = child->wait();
709*11be35a1SLionel Sambuc ATF_REQUIRE(status.signaled());
710*11be35a1SLionel Sambuc ATF_REQUIRE_EQ(SIGABRT, status.termsig());
711*11be35a1SLionel Sambuc }
712*11be35a1SLionel Sambuc
713*11be35a1SLionel Sambuc
714*11be35a1SLionel Sambuc ATF_TEST_CASE_WITHOUT_HEAD(child__pid);
ATF_TEST_CASE_BODY(child__pid)715*11be35a1SLionel Sambuc ATF_TEST_CASE_BODY(child__pid)
716*11be35a1SLionel Sambuc {
717*11be35a1SLionel Sambuc std::auto_ptr< process::child > child = process::child::fork_capture(
718*11be35a1SLionel Sambuc child_write_pid);
719*11be35a1SLionel Sambuc
720*11be35a1SLionel Sambuc const int pid = child->pid();
721*11be35a1SLionel Sambuc
722*11be35a1SLionel Sambuc const process::status status = child->wait();
723*11be35a1SLionel Sambuc ATF_REQUIRE(status.exited());
724*11be35a1SLionel Sambuc ATF_REQUIRE_EQ(EXIT_SUCCESS, status.exitstatus());
725*11be35a1SLionel Sambuc
726*11be35a1SLionel Sambuc std::ifstream input("pidfile");
727*11be35a1SLionel Sambuc ATF_REQUIRE(input);
728*11be35a1SLionel Sambuc int read_pid;
729*11be35a1SLionel Sambuc input >> read_pid;
730*11be35a1SLionel Sambuc input.close();
731*11be35a1SLionel Sambuc
732*11be35a1SLionel Sambuc ATF_REQUIRE_EQ(read_pid, pid);
733*11be35a1SLionel Sambuc }
734*11be35a1SLionel Sambuc
735*11be35a1SLionel Sambuc
ATF_INIT_TEST_CASES(tcs)736*11be35a1SLionel Sambuc ATF_INIT_TEST_CASES(tcs)
737*11be35a1SLionel Sambuc {
738*11be35a1SLionel Sambuc ATF_ADD_TEST_CASE(tcs, child__fork_capture__ok_function);
739*11be35a1SLionel Sambuc ATF_ADD_TEST_CASE(tcs, child__fork_capture__ok_functor);
740*11be35a1SLionel Sambuc ATF_ADD_TEST_CASE(tcs, child__fork_capture__pipe_fail);
741*11be35a1SLionel Sambuc ATF_ADD_TEST_CASE(tcs, child__fork_capture__fork_cannot_exit);
742*11be35a1SLionel Sambuc ATF_ADD_TEST_CASE(tcs, child__fork_capture__fork_cannot_unwind);
743*11be35a1SLionel Sambuc ATF_ADD_TEST_CASE(tcs, child__fork_capture__fork_fail);
744*11be35a1SLionel Sambuc
745*11be35a1SLionel Sambuc ATF_ADD_TEST_CASE(tcs, child__fork_files__ok_function);
746*11be35a1SLionel Sambuc ATF_ADD_TEST_CASE(tcs, child__fork_files__ok_functor);
747*11be35a1SLionel Sambuc ATF_ADD_TEST_CASE(tcs, child__fork_files__inherit_stdout);
748*11be35a1SLionel Sambuc ATF_ADD_TEST_CASE(tcs, child__fork_files__inherit_stderr);
749*11be35a1SLionel Sambuc ATF_ADD_TEST_CASE(tcs, child__fork_files__fork_cannot_exit);
750*11be35a1SLionel Sambuc ATF_ADD_TEST_CASE(tcs, child__fork_files__fork_cannot_unwind);
751*11be35a1SLionel Sambuc ATF_ADD_TEST_CASE(tcs, child__fork_files__fork_fail);
752*11be35a1SLionel Sambuc ATF_ADD_TEST_CASE(tcs, child__fork_files__create_stdout_fail);
753*11be35a1SLionel Sambuc ATF_ADD_TEST_CASE(tcs, child__fork_files__create_stderr_fail);
754*11be35a1SLionel Sambuc
755*11be35a1SLionel Sambuc ATF_ADD_TEST_CASE(tcs, child__spawn__absolute_path);
756*11be35a1SLionel Sambuc ATF_ADD_TEST_CASE(tcs, child__spawn__relative_path);
757*11be35a1SLionel Sambuc ATF_ADD_TEST_CASE(tcs, child__spawn__basename_only);
758*11be35a1SLionel Sambuc ATF_ADD_TEST_CASE(tcs, child__spawn__no_path);
759*11be35a1SLionel Sambuc ATF_ADD_TEST_CASE(tcs, child__spawn__no_args);
760*11be35a1SLionel Sambuc ATF_ADD_TEST_CASE(tcs, child__spawn__some_args);
761*11be35a1SLionel Sambuc ATF_ADD_TEST_CASE(tcs, child__spawn__missing_program);
762*11be35a1SLionel Sambuc
763*11be35a1SLionel Sambuc ATF_ADD_TEST_CASE(tcs, child__pid);
764*11be35a1SLionel Sambuc }
765