• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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/error.hpp>
15 #include <boost/process/async.hpp>
16 #include <boost/process/io.hpp>
17 #include <boost/process/child.hpp>
18 
19 #include <boost/thread.hpp>
20 #include <future>
21 
22 #include <boost/system/error_code.hpp>
23 #include <boost/algorithm/string/predicate.hpp>
24 #include <boost/asio/deadline_timer.hpp>
25 
26 using namespace std;
27 
28 namespace bp = boost::process;
29 
30 #if __APPLE__
__anon052f0dbf0102(int)31 auto abort_sig = signal(SIGALRM, +[](int){std::terminate();});
32 #endif
33 
34 BOOST_AUTO_TEST_SUITE( async );
35 
36 
37 BOOST_AUTO_TEST_CASE(async_wait, *boost::unit_test::timeout(5))
38 {
39     using boost::unit_test::framework::master_test_suite;
40     using namespace boost::asio;
41 
42     boost::asio::io_context io_context;
43 
44     std::error_code ec;
45 
46     bool exit_called_for_c1 = false;
47     int exit_code_c1 = 0;
48 
49     boost::asio::deadline_timer timeout{io_context, boost::posix_time::seconds(2)};
__anon052f0dbf0202(boost::system::error_code ec)50     timeout.async_wait([&](boost::system::error_code ec){if (!ec) io_context.stop();});
51 
52     bp::child c1(master_test_suite().argv[1],
53                  "test", "--exit-code", "123",
54                  ec, io_context,
55                  bp::on_exit([&](int exit, const std::error_code& ec_in)
__anon052f0dbf0302(int exit, const std::error_code& ec_in) 56                              {
57                                  BOOST_CHECK(!exit_called_for_c1);
58                                  exit_code_c1 = exit; exit_called_for_c1=true;
59                                  BOOST_CHECK(!ec_in);
60                                  timeout.cancel();
61                              }));
62     BOOST_REQUIRE(!ec);
63 
64     bool exit_called_for_c2 = false;
65     int exit_code_c2 = 0;
66     bp::child c2(master_test_suite().argv[1],
67                  "test", "--exit-code", "21",
68                  ec, io_context,
69                  bp::on_exit([&](int exit, const std::error_code& ec_in)
__anon052f0dbf0402(int exit, const std::error_code& ec_in) 70                             {
71                                 BOOST_CHECK(!exit_called_for_c2);
72                                 exit_code_c2 = exit; exit_called_for_c2=true;
73                                 BOOST_CHECK(!ec_in);
74                             })
75                 );
76     BOOST_REQUIRE(!ec);
77 
78     io_context.run();
79 
80     BOOST_CHECK(exit_called_for_c1);
81     BOOST_CHECK_EQUAL(exit_code_c1, 123);
82     BOOST_CHECK_EQUAL(c1.exit_code(), 123);
83 
84     BOOST_CHECK(exit_called_for_c2);
85     BOOST_CHECK_EQUAL(exit_code_c2, 21);
86     BOOST_CHECK_EQUAL(c2.exit_code(), 21);
87 }
88 
89 BOOST_AUTO_TEST_CASE(async_wait_sync_wait, *boost::unit_test::timeout(5))
90 {
91     using boost::unit_test::framework::master_test_suite;
92     using namespace boost::asio;
93 
94     boost::asio::io_context io_context;
95 
96     bool exit_called = false;
97     int exit_code = 0;
98     std::error_code ec;
99 
100     boost::asio::deadline_timer timeout{io_context, boost::posix_time::seconds(3)};
__anon052f0dbf0502(boost::system::error_code ec)101     timeout.async_wait([&](boost::system::error_code ec){if (!ec) io_context.stop();});
102 
103     bp::child c1(
104         master_test_suite().argv[1],
105         "test", "--exit-code", "1",
106         ec
107     );
108     BOOST_REQUIRE(!ec);
109 
110     bp::child c2(
111         master_test_suite().argv[1],
112         "test", "--exit-code", "2", "--wait", "1",
113         ec,
114         io_context,
115         bp::on_exit([&](int exit, const std::error_code& ec_in)
__anon052f0dbf0602(int exit, const std::error_code& ec_in) 116                 {
117                     exit_code = exit; exit_called=true;
118                     BOOST_CHECK(!ec_in);
119                     timeout.cancel();
120                 })
121     );
122     BOOST_REQUIRE(!ec);
123 
124     io_context.run();
125     // Regression test for #143: make sure the async SIGCHLD handler on POSIX does not reap the
126     // child c1 is watching (this will error if so)
127     c1.wait(ec);
128     BOOST_REQUIRE(!ec);
129 
130     BOOST_CHECK(exit_called);
131     BOOST_CHECK_EQUAL(exit_code, 2);
132     BOOST_CHECK_EQUAL(c2.exit_code(), 2);
133 }
134 
135 BOOST_AUTO_TEST_CASE(async_wait_different_contexts, *boost::unit_test::timeout(10))
136 {
137     using boost::unit_test::framework::master_test_suite;
138     using namespace boost::asio;
139 
140     boost::asio::io_context io_context1;
141     boost::asio::io_context io_context2;
142 
143     boost::asio::deadline_timer timeout1{io_context1, boost::posix_time::seconds(2)};
__anon052f0dbf0702(boost::system::error_code ec)144     timeout1.async_wait([&](boost::system::error_code ec){if (!ec) io_context1.stop();});
145 
146     boost::asio::deadline_timer timeout2{io_context2, boost::posix_time::seconds(7)};
__anon052f0dbf0802(boost::system::error_code ec)147     timeout2.async_wait([&](boost::system::error_code ec){if (!ec) io_context2.stop();});
148     std::error_code ec;
149 
150     bool exit_called_for_c1 = false;
151     int exit_code_c1 = 0;
152     bp::child c1(
153         master_test_suite().argv[1],
154         "test", "--exit-code", "1",
155         ec,
156         io_context1,
157         bp::on_exit([&](int exit, const std::error_code& ec_in)
__anon052f0dbf0902(int exit, const std::error_code& ec_in) 158                 {
159                     BOOST_CHECK(!exit_called_for_c1);
160                     exit_code_c1 = exit; exit_called_for_c1=true;
161                     BOOST_CHECK(!ec_in);
162                     timeout1.cancel();
163                 })
164     );
165     BOOST_REQUIRE(!ec);
166 
167     bool exit_called_for_c2 = false;
168     int exit_code_c2 = 0;
169     bp::child c2(
170         master_test_suite().argv[1],
171         "test", "--exit-code", "2", "--wait", "4",
172         ec,
173         io_context2,
174         bp::on_exit([&](int exit, const std::error_code& ec_in)
__anon052f0dbf0a02(int exit, const std::error_code& ec_in) 175                 {
176                     BOOST_CHECK(!exit_called_for_c2);
177                     exit_code_c2 = exit; exit_called_for_c2=true;
178                     BOOST_CHECK(!ec_in);
179                     timeout2.cancel();
180                 })
181     );
182     BOOST_REQUIRE(!ec);
183 
184     // Regression test for #143: make sure each io_context handles its own children
__anon052f0dbf0b02null185     std::thread thr1{[&]{io_context1.run();}};
__anon052f0dbf0c02null186     std::thread thr2{[&]{io_context2.run();}};
187 
188     thr1.join();
189     thr2.join();
190     c1.wait(ec);
191     BOOST_REQUIRE(!ec);
192 
193     BOOST_CHECK(exit_called_for_c1);
194     BOOST_CHECK_EQUAL(exit_code_c1, 1);
195     BOOST_CHECK_EQUAL(c1.exit_code(), 1);
196     BOOST_CHECK(exit_called_for_c2);
197     BOOST_CHECK_EQUAL(exit_code_c2, 2);
198     BOOST_CHECK_EQUAL(c2.exit_code(), 2);
199 }
200 
201 BOOST_AUTO_TEST_CASE(async_wait_abort, *boost::unit_test::timeout(5))
202 {
203     using boost::unit_test::framework::master_test_suite;
204     using namespace boost::asio;
205 
206     boost::asio::io_context io_context;
207 
208     std::error_code ec;
209 
210     boost::asio::deadline_timer timeout{io_context, boost::posix_time::seconds(5)};
__anon052f0dbf0d02(boost::system::error_code ec)211     timeout.async_wait([&](boost::system::error_code ec){if (!ec) io_context.stop();});
212 
213     bool exit_called = false;
214     int exit_code = 0;
215     bp::child c(
216         master_test_suite().argv[1],
217         "test", "--abort",
218         ec,
219         io_context,
220         bp::on_exit([&](int exit, const std::error_code& ec_in)
__anon052f0dbf0e02(int exit, const std::error_code& ec_in) 221                 {
222                     BOOST_CHECK(!exit_called);
223                     exit_code = exit;
224                     exit_called=true;
225                     BOOST_TEST_MESSAGE(ec_in.message());
226                     BOOST_CHECK(!ec_in);
227                     timeout.cancel();
228                 })
229     );
230     BOOST_REQUIRE(!ec);
231 
232     io_context.run();
233 
234     BOOST_CHECK(exit_called);
235     BOOST_CHECK_NE(exit_code,  0);
236     BOOST_CHECK_EQUAL(c.exit_code(), exit_code);
237 }
238 
239 
240 BOOST_AUTO_TEST_CASE(async_future, *boost::unit_test::timeout(3))
241 {
242     using boost::unit_test::framework::master_test_suite;
243     using namespace boost::asio;
244 
245     boost::asio::io_context io_context;
246 
247     boost::asio::deadline_timer timeout{io_context, boost::posix_time::seconds(2)};
__anon052f0dbf0f02(boost::system::error_code ec)248     timeout.async_wait([&](boost::system::error_code ec){if (!ec) io_context.stop();});
249 
250     std::error_code ec;
251     std::future<int> fut;
252     bp::child c(
253         master_test_suite().argv[1],
254         "test", "--exit-code", "42",
255         ec,
256         io_context,
257         bp::on_exit=fut
258     );
259 
260     BOOST_REQUIRE(!ec);
261 
262     io_context.run();
263 
264     BOOST_REQUIRE(fut.valid());
265     BOOST_CHECK_EQUAL(fut.get(), 42);
266 }
267 
268 
269 BOOST_AUTO_TEST_CASE(async_out_stream, *boost::unit_test::timeout(5))
270 {
271     using boost::unit_test::framework::master_test_suite;
272 
273     boost::asio::io_context io_context;
274 
275 
276     std::error_code ec;
277 
278     boost::asio::streambuf buf;
279 
280     boost::asio::deadline_timer timeout{io_context, boost::posix_time::seconds(2)};
__anon052f0dbf1002(boost::system::error_code ec)281     timeout.async_wait([&](boost::system::error_code ec){if (!ec) io_context.stop();});
282 
283     bp::child c(master_test_suite().argv[1],
284                 "test", "--echo-stdout", "abc",
285                 bp::std_out > buf,
286                 io_context,
287                 ec);
288     BOOST_REQUIRE(!ec);
289 
290     io_context.run();
291 
292     std::istream istr(&buf);
293 
294     std::string line;
295     std::getline(istr, line);
296     BOOST_REQUIRE_GE(line.size(), 3u);
297     BOOST_CHECK(boost::algorithm::starts_with(line, "abc"));
298     c.wait();
299 }
300 
301 
302 
303 BOOST_AUTO_TEST_CASE(async_in_stream, *boost::unit_test::timeout(5))
304 {
305 
306     using boost::unit_test::framework::master_test_suite;
307 
308     boost::asio::io_context io_context;
309 
310 
311     std::error_code ec;
312 
313     boost::asio::streambuf buf;
314     boost::asio::streambuf in_buf;
315 
316 
317     std::ostream ostr(&in_buf);
318     ostr << "-string" << endl ;
319 
320     boost::asio::deadline_timer timeout{io_context, boost::posix_time::seconds(2)};
__anon052f0dbf1102(boost::system::error_code ec)321     timeout.async_wait([&](boost::system::error_code ec){if (!ec) io_context.stop();});
322 
323     bp::child c(
324         master_test_suite().argv[1],
325         "test", "--prefix-once", "test",
326         bp::std_in  < in_buf,
327         bp::std_out > buf,
328         io_context,
329         ec
330     );
331     BOOST_REQUIRE(!ec);
332 
333     io_context.run();
334 
335     std::istream istr(&buf);
336 
337     std::string line;
338     std::getline(istr, line);
339 
340     std::string val = "test-string";
341     BOOST_REQUIRE_GE(line.size(), val.size());
342     if (line >= val)
343         BOOST_CHECK(boost::algorithm::starts_with(line, val));
344 
345 
346     c.wait();
347 }
348 
349 
350 BOOST_AUTO_TEST_CASE(async_error, *boost::unit_test::timeout(3))
351 {
352     using boost::unit_test::framework::master_test_suite;
353     using namespace boost::asio;
354 
355     boost::asio::io_context io_context;
356 
357     boost::asio::deadline_timer timeout{io_context, boost::posix_time::seconds(2)};
__anon052f0dbf1202(boost::system::error_code ec)358     timeout.async_wait([&](boost::system::error_code ec){if (!ec) io_context.stop();});
359 
360     bool exit_called = false;
361     std::error_code ec;
362     bp::child c(
363         "doesn't exist",
364         ec,
365         io_context,
366         bp::on_exit([&](int exit, const std::error_code& ec_in)
__anon052f0dbf1302(int exit, const std::error_code& ec_in) 367                 {
368                     exit_called=true;
369                 })
370     );
371 
372     BOOST_REQUIRE(ec);
373 
374     io_context.run();
375 
376     BOOST_CHECK(!exit_called);
377 }
378 
379 
380 /*
381 BOOST_AUTO_TEST_CASE(mixed_async, *boost::unit_test::timeout(5))
382 {
383     using boost::unit_test::framework::master_test_suite;
384     using namespace boost::asio;
385 
386     boost::asio::io_context io_context;
387 
388     boost::asio::deadline_timer timeout{io_context, boost::posix_time::seconds(2)};
389     timeout.async_wait([&](boost::system::error_code ec){if (!ec) io_context.stop();});
390 
391     bool exit_called = false;
392     std::error_code ec;
393 
394     bp::child c(master_test_suite().argv[1],
395             "--wait", "1", "--exit-code", "42",
396             ec,
397             io_context,
398             bp::on_exit([&](int exit, const std::error_code& ec_in)
399                         {
400                             timeout.cancel();
401                             exit_called=true;
402                             BOOST_CHECK_EQUAL(exit, 42);
403                         })
404     );
405 
406     BOOST_REQUIRE(!ec);
407     std::thread thr([&]{c.wait();});
408     io_context.run();
409 
410     BOOST_CHECK(exit_called);
411     BOOST_CHECK_EQUAL(c.exit_code(), 42);
412     thr.join();
413 
414 }*/
415 
416 BOOST_AUTO_TEST_SUITE_END();
417