1 // Copyright (c) 2006, 2007 Julio M. Merino Vidal 2 // Copyright (c) 2008 Ilya Sokolov, Boris Schaeling 3 // Copyright (c) 2009 Boris Schaeling 4 // Copyright (c) 2010 Felipe Tanus, Boris Schaeling 5 // Copyright (c) 2011, 2012 Jeff Flinn, Boris Schaeling 6 // 7 // Distributed under the Boost Software License, Version 1.0. (See accompanying 8 // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) 9 10 #define BOOST_TEST_MAIN 11 #define BOOST_TEST_IGNORE_SIGCHLD 12 #include <boost/test/included/unit_test.hpp> 13 14 #include <boost/process.hpp> 15 #include <boost/process/posix.hpp> 16 17 #include <boost/filesystem.hpp> 18 19 #include <system_error> 20 21 22 #include <string> 23 #include <sys/wait.h> 24 #include <errno.h> 25 26 namespace fs = boost::filesystem; 27 namespace bp = boost::process; 28 29 BOOST_AUTO_TEST_CASE(bind_fd, *boost::unit_test::timeout(2)) 30 { 31 using boost::unit_test::framework::master_test_suite; 32 33 bp::pipe p; 34 35 std::error_code ec; 36 bp::child c( 37 master_test_suite().argv[1], 38 "test", "--posix-echo-one", "3", "hello", 39 bp::posix::fd.bind(3, p.native_sink()), 40 ec 41 ); 42 BOOST_CHECK(!ec); 43 44 45 bp::ipstream is(std::move(p)); 46 47 std::string s; 48 is >> s; 49 BOOST_CHECK_EQUAL(s, "hello"); 50 } 51 52 BOOST_AUTO_TEST_CASE(bind_fds, *boost::unit_test::timeout(2)) 53 { 54 using boost::unit_test::framework::master_test_suite; 55 56 bp::pipe p1; 57 bp::pipe p2; 58 59 std::error_code ec; 60 bp::child c( 61 master_test_suite().argv[1], 62 "test","--posix-echo-two","3","hello","99","bye", 63 bp::posix::fd.bind(3, p1.native_sink()), 64 bp::posix::fd.bind(99, p2.native_sink()), 65 ec 66 ); 67 BOOST_CHECK(!ec); 68 69 bp::ipstream is1(std::move(p1)); 70 bp::ipstream is2(std::move(p2)); 71 72 std::string s1; 73 is1 >> s1; 74 BOOST_CHECK_EQUAL(s1, "hello"); 75 76 std::string s2; 77 is2 >> s2; 78 BOOST_CHECK_EQUAL(s2, "bye"); 79 } 80 81 BOOST_AUTO_TEST_CASE(execve_set_on_error, *boost::unit_test::timeout(2)) 82 { 83 std::error_code ec; 84 bp::spawn( 85 "doesnt-exist", 86 ec 87 ); 88 BOOST_CHECK(ec); 89 BOOST_CHECK_EQUAL(ec.value(), ENOENT); 90 } 91 92 BOOST_AUTO_TEST_CASE(execve_throw_on_error, *boost::unit_test::timeout(2)) 93 { 94 try 95 { 96 bp::spawn("doesnt-exist"); 97 BOOST_CHECK(false); 98 } 99 catch (bp::process_error &e) 100 { 101 BOOST_CHECK(e.code()); 102 BOOST_CHECK_EQUAL(e.code().value(), ENOENT); 103 } 104 } 105 106 BOOST_AUTO_TEST_CASE(leak_test, *boost::unit_test::timeout(5)) 107 { 108 using boost::unit_test::framework::master_test_suite; 109 110 std::error_code ec; 111 112 const auto pid = boost::this_process::get_id(); 113 const auto fd_path = fs::path("/proc") / std::to_string(pid) / "fd"; 114 __anondf27bc370102null115 auto get_fds = [&]{ 116 std::vector<int> fds; 117 for (auto && fd : fs::directory_iterator(fd_path)) 118 fds.push_back(std::stoi(fd.path().filename().string())); 119 return fds; 120 }; 121 122 std::vector<int> fd_list = get_fds(); 123 if (fd_list.empty()) //then there's no /proc in the current linux distribution. 124 return; 125 126 127 BOOST_CHECK(std::find(fd_list.begin(), fd_list.end(), STDOUT_FILENO) != fd_list.end()); 128 BOOST_CHECK(std::find(fd_list.begin(), fd_list.end(), STDIN_FILENO) != fd_list.end()); 129 BOOST_CHECK(std::find(fd_list.begin(), fd_list.end(), STDERR_FILENO) != fd_list.end()); 130 131 bp::pipe p; //should add two descriptors. 132 133 auto fd_list_new = get_fds(); 134 135 BOOST_CHECK_EQUAL(fd_list_new.size(), fd_list.size() + 2); 136 fd_list.push_back(p.native_source()); 137 fd_list.push_back(p.native_sink()); 138 139 140 BOOST_CHECK_EQUAL( 141 bp::system( 142 master_test_suite().argv[1], 143 "test", "--exit-code", "123", ec), 123); 144 145 fd_list_new = get_fds(); 146 BOOST_CHECK_EQUAL(fd_list.size(), fd_list_new.size()); 147 148 149 const int native_source = p.native_source(); 150 BOOST_CHECK_EQUAL( 151 bp::system( 152 master_test_suite().argv[1], 153 bp::std_in < p, 154 "test", "--exit-code", "123", ec), 123); 155 156 BOOST_CHECK(!ec); 157 158 ////now, p.source should be closed, so we remove it from fd_list 159 160 const auto itr = std::find(fd_list.begin(), fd_list.end(), native_source); 161 if (itr != fd_list.end()) 162 fd_list.erase(itr); 163 164 fd_list_new = get_fds(); 165 166 BOOST_CHECK_EQUAL(fd_list.size(), fd_list_new.size()); 167 168 }