1 // Copyright (c) 2019 Klemens D. Morgenstern
3 // Distributed under the Boost Software License, Version 1.0. (See accompanying
4 // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
6 #define BOOST_TEST_MAIN
7 #define BOOST_TEST_IGNORE_SIGCHLD
8 #include <boost/test/included/unit_test.hpp>
12 #include <boost/process.hpp>
13 #include <boost/process/handles.hpp>
14 #include <boost/process/pipe.hpp>
15 #include <boost/process/io.hpp>
16 #include <boost/process/async_pipe.hpp>
17 #include <boost/process/extend.hpp>
19 #include <boost/filesystem.hpp>
21 #include <system_error>
24 #include <boost/asio/ip/tcp.hpp>
25 #include <boost/asio/ip/udp.hpp>
27 #if defined(BOOST_WINDOWS_API)
28 #include <boost/winapi/get_current_thread.hpp>
29 #include <boost/winapi/get_current_process.hpp>
32 namespace fs
= boost::filesystem
;
33 namespace bp
= boost::process
;
34 namespace bt
= boost::this_process
;
36 BOOST_AUTO_TEST_CASE(leak_test
, *boost::unit_test::timeout(5))
38 using boost::unit_test::framework::master_test_suite
;
40 #if defined(BOOST_WINDOWS_API)
41 const auto get_handle
= [](FILE * f
) {return reinterpret_cast<bt::native_handle_type
>(_get_osfhandle(_fileno(f
)));};
42 const auto socket_to_handle
= [](::boost::winapi::UINT_PTR_ sock
){return reinterpret_cast<::boost::winapi::HANDLE_
>(sock
);};
44 const auto get_handle
= [](FILE * f
) {return fileno(f
);};
45 const auto socket_to_handle
= [](int i
){ return i
;};
49 auto fd_list
= bt::get_handles(ec
);
51 BOOST_CHECK_EQUAL(std::count(fd_list
.begin(), fd_list
.end(), get_handle(stdin
)), 1);
52 BOOST_CHECK_EQUAL(std::count(fd_list
.begin(), fd_list
.end(), get_handle(stdout
)), 1);
53 BOOST_CHECK_EQUAL(std::count(fd_list
.begin(), fd_list
.end(), get_handle(stderr
)), 1);
55 BOOST_CHECK(bt::is_stream_handle(get_handle(stdin
), ec
)); BOOST_CHECK_MESSAGE(!ec
, ec
.message());
56 BOOST_CHECK(bt::is_stream_handle(get_handle(stdout
), ec
)); BOOST_CHECK_MESSAGE(!ec
, ec
.message());
57 BOOST_CHECK(bt::is_stream_handle(get_handle(stderr
), ec
)); BOOST_CHECK_MESSAGE(!ec
, ec
.message());
60 BOOST_CHECK_GE(fd_list
.size(), 3u);
61 BOOST_CHECK_GE(bt::get_handles(ec
).size(), fd_list
.size());
67 auto fd_list_new
= bt::get_handles(ec
);
68 BOOST_CHECK_MESSAGE(!ec
, ec
);
69 BOOST_CHECK_LE(fd_list
.size() + 2u, fd_list_new
.size());
70 fd_list
= std::move(fd_list_new
);
75 BOOST_CHECK_EQUAL(std::count(fd_list
.begin(), fd_list
.end(), p
.native_source()), 1u);
76 BOOST_CHECK_EQUAL(std::count(fd_list
.begin(), fd_list
.end(), p
.native_sink()), 1u);
78 BOOST_CHECK(bt::is_stream_handle(p
.native_source(), ec
)); BOOST_CHECK_MESSAGE(!ec
, ec
.message());
79 BOOST_CHECK(bt::is_stream_handle(p
.native_sink(), ec
)); BOOST_CHECK_MESSAGE(!ec
, ec
.message());
83 fd_list
= bt::get_handles(ec
);
85 BOOST_CHECK_EQUAL(std::count(fd_list
.begin(), fd_list
.end(), p
.native_source()), 0u);
86 BOOST_CHECK_EQUAL(std::count(fd_list
.begin(), fd_list
.end(), p
.native_sink()), 0u);
88 #if defined( BOOST_WINDOWS_API )
89 std::thread
thr([]{});
90 BOOST_CHECK(!bt::is_stream_handle(thr
.native_handle(), ec
)); BOOST_CHECK_MESSAGE(!ec
, ec
.message());
93 # if defined(TFD_CLOEXEC) //check timer
94 int timer_fd
= ::timerfd_create(CLOCK_MONOTONIC
, TFD_CLOEXEC
);
95 BOOST_CHECK(!bt::is_stream_handle(timer_fd
, ec
)); BOOST_CHECK_MESSAGE(!ec
, ec
.message());
97 # if defined(EFD_CLOEXEC) && defined(EFD_NONBLOCK)
98 int event_fd
=::eventfd(0, EFD_CLOEXEC
| EFD_NONBLOCK
);
99 BOOST_CHECK(!bt::is_stream_handle(event_fd
, ec
)); BOOST_CHECK_MESSAGE(!ec
, ec
.message());
101 int dir_fd
= ::dirfd(::opendir("."));
102 BOOST_CHECK(!bt::is_stream_handle(dir_fd
, ec
)); BOOST_CHECK_MESSAGE(!ec
, ec
.message());
106 boost::asio::io_context ioc
;
107 boost::asio::ip::tcp::socket
tcp_socket(ioc
);
108 boost::asio::ip::udp::socket
udp_socket(ioc
);
109 bp::async_pipe
ap(ioc
);
111 tcp_socket
.open(boost::asio::ip::tcp::v4());
112 udp_socket
.open(boost::asio::ip::udp::v4());
114 BOOST_CHECK(bt::is_stream_handle(socket_to_handle(tcp_socket
.native_handle()), ec
)); BOOST_CHECK_MESSAGE(!ec
, ec
.message());
115 BOOST_CHECK(bt::is_stream_handle(socket_to_handle(udp_socket
.native_handle()), ec
)); BOOST_CHECK_MESSAGE(!ec
, ec
.message());
116 BOOST_CHECK(bt::is_stream_handle(std::move(ap
).sink(). native_handle(), ec
)); BOOST_CHECK_MESSAGE(!ec
, ec
.message());
117 BOOST_CHECK(bt::is_stream_handle(std::move(ap
).source().native_handle(), ec
)); BOOST_CHECK_MESSAGE(!ec
, ec
.message());
122 std::vector
<bt::native_handle_type
> &res
;
124 on_setup_t(std::vector
<bt::native_handle_type
> & res
) : res(res
) {}
125 template<typename Executor
>
126 void operator()(Executor
& e
)
128 bp::extend::foreach_used_handle(e
, [this](bt::native_handle_type handle
)
130 res
.push_back(handle
);
135 BOOST_AUTO_TEST_CASE(iterate_handles
, *boost::unit_test::timeout(5))
137 using boost::unit_test::framework::master_test_suite
;
139 std::vector
<bt::native_handle_type
> res
;
144 auto source
= p_in
.native_source();
145 auto sink
= p_out
.native_sink();
148 BOOST_WARN_NE(source
, sink
); //Sanity check
150 const auto ret
= bp::system(master_test_suite().argv
[1], "--exit-code" , "42",
153 bp::extend::on_setup(on_setup_t(res
)), ec
);
155 BOOST_CHECK_MESSAGE(!ec
, ec
.message());
157 BOOST_CHECK_EQUAL(ret
, 42u);
158 BOOST_CHECK_EQUAL(std::count(res
.begin(), res
.end(), p_in
. native_sink()), 0u);
159 BOOST_CHECK_EQUAL(std::count(res
.begin(), res
.end(), p_out
.native_source()), 0u);
162 BOOST_AUTO_TEST_CASE(limit_fd
, *boost::unit_test::timeout(5))
164 #if defined(BOOST_WINDOWS_API)
165 const auto get_handle
= [](FILE * f
){return std::to_string(_get_osfhandle(_fileno(f
)));};
167 const auto get_handle
= [](FILE * f
){return std::to_string(fileno(f
));};
170 auto p
= fopen("./test-file", "w");
172 using boost::unit_test::framework::master_test_suite
;
174 BOOST_CHECK_EQUAL(bp::system(master_test_suite().argv
[1], "--has-handle", bp::limit_handles
, get_handle(p
), bp::std_in
< p
), EXIT_SUCCESS
);
175 BOOST_CHECK_EQUAL(bp::system(master_test_suite().argv
[1], "--has-handle", bp::limit_handles
, get_handle(p
), bp::std_err
> p
), EXIT_SUCCESS
);
176 BOOST_CHECK_EQUAL(bp::system(master_test_suite().argv
[1], "--has-handle", bp::limit_handles
, get_handle(p
), bp::std_out
> p
), EXIT_SUCCESS
);
177 BOOST_CHECK_EQUAL(bp::system(master_test_suite().argv
[1], "--has-handle", bp::limit_handles
, get_handle(p
)), EXIT_FAILURE
);