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