xref: /netbsd/external/bsd/atf/dist/tools/io_test.cpp (revision ee44dd6c)
1*ee44dd6cSjmmv //
2*ee44dd6cSjmmv // Automated Testing Framework (atf)
3*ee44dd6cSjmmv //
4*ee44dd6cSjmmv // Copyright (c) 2007 The NetBSD Foundation, Inc.
5*ee44dd6cSjmmv // All rights reserved.
6*ee44dd6cSjmmv //
7*ee44dd6cSjmmv // Redistribution and use in source and binary forms, with or without
8*ee44dd6cSjmmv // modification, are permitted provided that the following conditions
9*ee44dd6cSjmmv // are met:
10*ee44dd6cSjmmv // 1. Redistributions of source code must retain the above copyright
11*ee44dd6cSjmmv //    notice, this list of conditions and the following disclaimer.
12*ee44dd6cSjmmv // 2. Redistributions in binary form must reproduce the above copyright
13*ee44dd6cSjmmv //    notice, this list of conditions and the following disclaimer in the
14*ee44dd6cSjmmv //    documentation and/or other materials provided with the distribution.
15*ee44dd6cSjmmv //
16*ee44dd6cSjmmv // THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND
17*ee44dd6cSjmmv // CONTRIBUTORS ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES,
18*ee44dd6cSjmmv // INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
19*ee44dd6cSjmmv // MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
20*ee44dd6cSjmmv // IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS BE LIABLE FOR ANY
21*ee44dd6cSjmmv // DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
22*ee44dd6cSjmmv // DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
23*ee44dd6cSjmmv // GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
24*ee44dd6cSjmmv // INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER
25*ee44dd6cSjmmv // IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
26*ee44dd6cSjmmv // OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
27*ee44dd6cSjmmv // IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
28*ee44dd6cSjmmv //
29*ee44dd6cSjmmv 
30*ee44dd6cSjmmv extern "C" {
31*ee44dd6cSjmmv #include <sys/stat.h>
32*ee44dd6cSjmmv #include <sys/wait.h>
33*ee44dd6cSjmmv 
34*ee44dd6cSjmmv #include <fcntl.h>
35*ee44dd6cSjmmv #include <unistd.h>
36*ee44dd6cSjmmv }
37*ee44dd6cSjmmv 
38*ee44dd6cSjmmv #include <cassert>
39*ee44dd6cSjmmv #include <cerrno>
40*ee44dd6cSjmmv #include <cstddef>
41*ee44dd6cSjmmv #include <cstdlib>
42*ee44dd6cSjmmv #include <cstring>
43*ee44dd6cSjmmv #include <fstream>
44*ee44dd6cSjmmv #include <iostream>
45*ee44dd6cSjmmv #include <istream>
46*ee44dd6cSjmmv #include <ostream>
47*ee44dd6cSjmmv 
48*ee44dd6cSjmmv #include <atf-c++.hpp>
49*ee44dd6cSjmmv 
50*ee44dd6cSjmmv #include "io.hpp"
51*ee44dd6cSjmmv #include "signals.hpp"
52*ee44dd6cSjmmv 
53*ee44dd6cSjmmv // ------------------------------------------------------------------------
54*ee44dd6cSjmmv // Auxiliary functions.
55*ee44dd6cSjmmv // ------------------------------------------------------------------------
56*ee44dd6cSjmmv 
57*ee44dd6cSjmmv static
58*ee44dd6cSjmmv void
systembuf_check_data(std::istream & is,std::size_t length)59*ee44dd6cSjmmv systembuf_check_data(std::istream& is, std::size_t length)
60*ee44dd6cSjmmv {
61*ee44dd6cSjmmv     char ch = 'A', chr;
62*ee44dd6cSjmmv     std::size_t cnt = 0;
63*ee44dd6cSjmmv     while (is >> chr) {
64*ee44dd6cSjmmv         ATF_REQUIRE_EQ(ch, chr);
65*ee44dd6cSjmmv         if (ch == 'Z')
66*ee44dd6cSjmmv             ch = 'A';
67*ee44dd6cSjmmv         else
68*ee44dd6cSjmmv             ch++;
69*ee44dd6cSjmmv         cnt++;
70*ee44dd6cSjmmv     }
71*ee44dd6cSjmmv     ATF_REQUIRE_EQ(cnt, length);
72*ee44dd6cSjmmv }
73*ee44dd6cSjmmv 
74*ee44dd6cSjmmv static
75*ee44dd6cSjmmv void
systembuf_write_data(std::ostream & os,std::size_t length)76*ee44dd6cSjmmv systembuf_write_data(std::ostream& os, std::size_t length)
77*ee44dd6cSjmmv {
78*ee44dd6cSjmmv     char ch = 'A';
79*ee44dd6cSjmmv     for (std::size_t i = 0; i < length; i++) {
80*ee44dd6cSjmmv         os << ch;
81*ee44dd6cSjmmv         if (ch == 'Z')
82*ee44dd6cSjmmv             ch = 'A';
83*ee44dd6cSjmmv         else
84*ee44dd6cSjmmv             ch++;
85*ee44dd6cSjmmv     }
86*ee44dd6cSjmmv     os.flush();
87*ee44dd6cSjmmv }
88*ee44dd6cSjmmv 
89*ee44dd6cSjmmv static
90*ee44dd6cSjmmv void
systembuf_test_read(std::size_t length,std::size_t bufsize)91*ee44dd6cSjmmv systembuf_test_read(std::size_t length, std::size_t bufsize)
92*ee44dd6cSjmmv {
93*ee44dd6cSjmmv     using tools::io::systembuf;
94*ee44dd6cSjmmv 
95*ee44dd6cSjmmv     std::ofstream f("test_read.txt");
96*ee44dd6cSjmmv     systembuf_write_data(f, length);
97*ee44dd6cSjmmv     f.close();
98*ee44dd6cSjmmv 
99*ee44dd6cSjmmv     int fd = ::open("test_read.txt", O_RDONLY);
100*ee44dd6cSjmmv     ATF_REQUIRE(fd != -1);
101*ee44dd6cSjmmv     systembuf sb(fd, bufsize);
102*ee44dd6cSjmmv     std::istream is(&sb);
103*ee44dd6cSjmmv     systembuf_check_data(is, length);
104*ee44dd6cSjmmv     ::close(fd);
105*ee44dd6cSjmmv     ::unlink("test_read.txt");
106*ee44dd6cSjmmv }
107*ee44dd6cSjmmv 
108*ee44dd6cSjmmv static
109*ee44dd6cSjmmv void
systembuf_test_write(std::size_t length,std::size_t bufsize)110*ee44dd6cSjmmv systembuf_test_write(std::size_t length, std::size_t bufsize)
111*ee44dd6cSjmmv {
112*ee44dd6cSjmmv     using tools::io::systembuf;
113*ee44dd6cSjmmv 
114*ee44dd6cSjmmv     int fd = ::open("test_write.txt", O_WRONLY | O_CREAT | O_TRUNC,
115*ee44dd6cSjmmv                     S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH);
116*ee44dd6cSjmmv     ATF_REQUIRE(fd != -1);
117*ee44dd6cSjmmv     systembuf sb(fd, bufsize);
118*ee44dd6cSjmmv     std::ostream os(&sb);
119*ee44dd6cSjmmv     systembuf_write_data(os, length);
120*ee44dd6cSjmmv     ::close(fd);
121*ee44dd6cSjmmv 
122*ee44dd6cSjmmv     std::ifstream is("test_write.txt");
123*ee44dd6cSjmmv     systembuf_check_data(is, length);
124*ee44dd6cSjmmv     is.close();
125*ee44dd6cSjmmv     ::unlink("test_write.txt");
126*ee44dd6cSjmmv }
127*ee44dd6cSjmmv 
128*ee44dd6cSjmmv // ------------------------------------------------------------------------
129*ee44dd6cSjmmv // Test cases for the "file_handle" class.
130*ee44dd6cSjmmv // ------------------------------------------------------------------------
131*ee44dd6cSjmmv 
132*ee44dd6cSjmmv ATF_TEST_CASE(file_handle_ctor);
ATF_TEST_CASE_HEAD(file_handle_ctor)133*ee44dd6cSjmmv ATF_TEST_CASE_HEAD(file_handle_ctor)
134*ee44dd6cSjmmv {
135*ee44dd6cSjmmv     set_md_var("descr", "Tests file_handle's constructors");
136*ee44dd6cSjmmv }
ATF_TEST_CASE_BODY(file_handle_ctor)137*ee44dd6cSjmmv ATF_TEST_CASE_BODY(file_handle_ctor)
138*ee44dd6cSjmmv {
139*ee44dd6cSjmmv     using tools::io::file_handle;
140*ee44dd6cSjmmv 
141*ee44dd6cSjmmv     file_handle fh1;
142*ee44dd6cSjmmv     ATF_REQUIRE(!fh1.is_valid());
143*ee44dd6cSjmmv 
144*ee44dd6cSjmmv     file_handle fh2(STDOUT_FILENO);
145*ee44dd6cSjmmv     ATF_REQUIRE(fh2.is_valid());
146*ee44dd6cSjmmv     fh2.disown();
147*ee44dd6cSjmmv }
148*ee44dd6cSjmmv 
149*ee44dd6cSjmmv ATF_TEST_CASE(file_handle_copy);
ATF_TEST_CASE_HEAD(file_handle_copy)150*ee44dd6cSjmmv ATF_TEST_CASE_HEAD(file_handle_copy)
151*ee44dd6cSjmmv {
152*ee44dd6cSjmmv     set_md_var("descr", "Tests file_handle's copy constructor");
153*ee44dd6cSjmmv }
ATF_TEST_CASE_BODY(file_handle_copy)154*ee44dd6cSjmmv ATF_TEST_CASE_BODY(file_handle_copy)
155*ee44dd6cSjmmv {
156*ee44dd6cSjmmv     using tools::io::file_handle;
157*ee44dd6cSjmmv 
158*ee44dd6cSjmmv     file_handle fh1;
159*ee44dd6cSjmmv     file_handle fh2(STDOUT_FILENO);
160*ee44dd6cSjmmv 
161*ee44dd6cSjmmv     file_handle fh3(fh2);
162*ee44dd6cSjmmv     ATF_REQUIRE(!fh2.is_valid());
163*ee44dd6cSjmmv     ATF_REQUIRE(fh3.is_valid());
164*ee44dd6cSjmmv 
165*ee44dd6cSjmmv     fh1 = fh3;
166*ee44dd6cSjmmv     ATF_REQUIRE(!fh3.is_valid());
167*ee44dd6cSjmmv     ATF_REQUIRE(fh1.is_valid());
168*ee44dd6cSjmmv 
169*ee44dd6cSjmmv     fh1.disown();
170*ee44dd6cSjmmv }
171*ee44dd6cSjmmv 
172*ee44dd6cSjmmv ATF_TEST_CASE(file_handle_get);
ATF_TEST_CASE_HEAD(file_handle_get)173*ee44dd6cSjmmv ATF_TEST_CASE_HEAD(file_handle_get)
174*ee44dd6cSjmmv {
175*ee44dd6cSjmmv     set_md_var("descr", "Tests the file_handle::get method");
176*ee44dd6cSjmmv }
ATF_TEST_CASE_BODY(file_handle_get)177*ee44dd6cSjmmv ATF_TEST_CASE_BODY(file_handle_get)
178*ee44dd6cSjmmv {
179*ee44dd6cSjmmv     using tools::io::file_handle;
180*ee44dd6cSjmmv 
181*ee44dd6cSjmmv     file_handle fh1(STDOUT_FILENO);
182*ee44dd6cSjmmv     ATF_REQUIRE_EQ(fh1.get(), STDOUT_FILENO);
183*ee44dd6cSjmmv }
184*ee44dd6cSjmmv 
185*ee44dd6cSjmmv ATF_TEST_CASE(file_handle_posix_remap);
ATF_TEST_CASE_HEAD(file_handle_posix_remap)186*ee44dd6cSjmmv ATF_TEST_CASE_HEAD(file_handle_posix_remap)
187*ee44dd6cSjmmv {
188*ee44dd6cSjmmv     set_md_var("descr", "Tests the file_handle::posix_remap method");
189*ee44dd6cSjmmv }
ATF_TEST_CASE_BODY(file_handle_posix_remap)190*ee44dd6cSjmmv ATF_TEST_CASE_BODY(file_handle_posix_remap)
191*ee44dd6cSjmmv {
192*ee44dd6cSjmmv     using tools::io::file_handle;
193*ee44dd6cSjmmv 
194*ee44dd6cSjmmv     int pfd[2];
195*ee44dd6cSjmmv 
196*ee44dd6cSjmmv     ATF_REQUIRE(::pipe(pfd) != -1);
197*ee44dd6cSjmmv     file_handle rend(pfd[0]);
198*ee44dd6cSjmmv     file_handle wend(pfd[1]);
199*ee44dd6cSjmmv 
200*ee44dd6cSjmmv     ATF_REQUIRE(rend.get() != 10);
201*ee44dd6cSjmmv     ATF_REQUIRE(wend.get() != 10);
202*ee44dd6cSjmmv     wend.posix_remap(10);
203*ee44dd6cSjmmv     ATF_REQUIRE_EQ(wend.get(), 10);
204*ee44dd6cSjmmv     ATF_REQUIRE(::write(wend.get(), "test-posix-remap", 16) != -1);
205*ee44dd6cSjmmv     {
206*ee44dd6cSjmmv         char buf[17];
207*ee44dd6cSjmmv         ATF_REQUIRE_EQ(::read(rend.get(), buf, sizeof(buf)), 16);
208*ee44dd6cSjmmv         buf[16] = '\0';
209*ee44dd6cSjmmv         ATF_REQUIRE(std::strcmp(buf, "test-posix-remap") == 0);
210*ee44dd6cSjmmv     }
211*ee44dd6cSjmmv 
212*ee44dd6cSjmmv     // Redo previous to ensure that remapping over the same descriptor
213*ee44dd6cSjmmv     // has no side-effects.
214*ee44dd6cSjmmv     ATF_REQUIRE_EQ(wend.get(), 10);
215*ee44dd6cSjmmv     wend.posix_remap(10);
216*ee44dd6cSjmmv     ATF_REQUIRE_EQ(wend.get(), 10);
217*ee44dd6cSjmmv     ATF_REQUIRE(::write(wend.get(), "test-posix-remap", 16) != -1);
218*ee44dd6cSjmmv     {
219*ee44dd6cSjmmv         char buf[17];
220*ee44dd6cSjmmv         ATF_REQUIRE_EQ(::read(rend.get(), buf, sizeof(buf)), 16);
221*ee44dd6cSjmmv         buf[16] = '\0';
222*ee44dd6cSjmmv         ATF_REQUIRE(std::strcmp(buf, "test-posix-remap") == 0);
223*ee44dd6cSjmmv     }
224*ee44dd6cSjmmv }
225*ee44dd6cSjmmv 
226*ee44dd6cSjmmv // ------------------------------------------------------------------------
227*ee44dd6cSjmmv // Test cases for the "systembuf" class.
228*ee44dd6cSjmmv // ------------------------------------------------------------------------
229*ee44dd6cSjmmv 
230*ee44dd6cSjmmv ATF_TEST_CASE(systembuf_short_read);
ATF_TEST_CASE_HEAD(systembuf_short_read)231*ee44dd6cSjmmv ATF_TEST_CASE_HEAD(systembuf_short_read)
232*ee44dd6cSjmmv {
233*ee44dd6cSjmmv     set_md_var("descr", "Tests that a short read (one that fits in the "
234*ee44dd6cSjmmv                "internal buffer) works when using systembuf");
235*ee44dd6cSjmmv }
ATF_TEST_CASE_BODY(systembuf_short_read)236*ee44dd6cSjmmv ATF_TEST_CASE_BODY(systembuf_short_read)
237*ee44dd6cSjmmv {
238*ee44dd6cSjmmv     systembuf_test_read(64, 1024);
239*ee44dd6cSjmmv }
240*ee44dd6cSjmmv 
241*ee44dd6cSjmmv ATF_TEST_CASE(systembuf_long_read);
ATF_TEST_CASE_HEAD(systembuf_long_read)242*ee44dd6cSjmmv ATF_TEST_CASE_HEAD(systembuf_long_read)
243*ee44dd6cSjmmv {
244*ee44dd6cSjmmv     set_md_var("descr", "Tests that a long read (one that does not fit in "
245*ee44dd6cSjmmv                "the internal buffer) works when using systembuf");
246*ee44dd6cSjmmv }
ATF_TEST_CASE_BODY(systembuf_long_read)247*ee44dd6cSjmmv ATF_TEST_CASE_BODY(systembuf_long_read)
248*ee44dd6cSjmmv {
249*ee44dd6cSjmmv     systembuf_test_read(64 * 1024, 1024);
250*ee44dd6cSjmmv }
251*ee44dd6cSjmmv 
252*ee44dd6cSjmmv ATF_TEST_CASE(systembuf_short_write);
ATF_TEST_CASE_HEAD(systembuf_short_write)253*ee44dd6cSjmmv ATF_TEST_CASE_HEAD(systembuf_short_write)
254*ee44dd6cSjmmv {
255*ee44dd6cSjmmv     set_md_var("descr", "Tests that a short write (one that fits in the "
256*ee44dd6cSjmmv                "internal buffer) works when using systembuf");
257*ee44dd6cSjmmv }
ATF_TEST_CASE_BODY(systembuf_short_write)258*ee44dd6cSjmmv ATF_TEST_CASE_BODY(systembuf_short_write)
259*ee44dd6cSjmmv {
260*ee44dd6cSjmmv     systembuf_test_write(64, 1024);
261*ee44dd6cSjmmv }
262*ee44dd6cSjmmv 
263*ee44dd6cSjmmv ATF_TEST_CASE(systembuf_long_write);
ATF_TEST_CASE_HEAD(systembuf_long_write)264*ee44dd6cSjmmv ATF_TEST_CASE_HEAD(systembuf_long_write)
265*ee44dd6cSjmmv {
266*ee44dd6cSjmmv     set_md_var("descr", "Tests that a long write (one that does not fit "
267*ee44dd6cSjmmv                "in the internal buffer) works when using systembuf");
268*ee44dd6cSjmmv }
ATF_TEST_CASE_BODY(systembuf_long_write)269*ee44dd6cSjmmv ATF_TEST_CASE_BODY(systembuf_long_write)
270*ee44dd6cSjmmv {
271*ee44dd6cSjmmv     systembuf_test_write(64 * 1024, 1024);
272*ee44dd6cSjmmv }
273*ee44dd6cSjmmv 
274*ee44dd6cSjmmv // ------------------------------------------------------------------------
275*ee44dd6cSjmmv // Test cases for the "pistream" class.
276*ee44dd6cSjmmv // ------------------------------------------------------------------------
277*ee44dd6cSjmmv 
278*ee44dd6cSjmmv ATF_TEST_CASE(pistream);
ATF_TEST_CASE_HEAD(pistream)279*ee44dd6cSjmmv ATF_TEST_CASE_HEAD(pistream)
280*ee44dd6cSjmmv {
281*ee44dd6cSjmmv     set_md_var("descr", "Tests the pistream class");
282*ee44dd6cSjmmv }
ATF_TEST_CASE_BODY(pistream)283*ee44dd6cSjmmv ATF_TEST_CASE_BODY(pistream)
284*ee44dd6cSjmmv {
285*ee44dd6cSjmmv     using tools::io::file_handle;
286*ee44dd6cSjmmv     using tools::io::pistream;
287*ee44dd6cSjmmv     using tools::io::systembuf;
288*ee44dd6cSjmmv 
289*ee44dd6cSjmmv     int fds[2];
290*ee44dd6cSjmmv     ATF_REQUIRE(::pipe(fds) != -1);
291*ee44dd6cSjmmv 
292*ee44dd6cSjmmv     pistream rend(fds[0]);
293*ee44dd6cSjmmv 
294*ee44dd6cSjmmv     systembuf wbuf(fds[1]);
295*ee44dd6cSjmmv     std::ostream wend(&wbuf);
296*ee44dd6cSjmmv 
297*ee44dd6cSjmmv     // XXX This assumes that the pipe's buffer is big enough to accept
298*ee44dd6cSjmmv     // the data written without blocking!
299*ee44dd6cSjmmv     wend << "1Test 1message\n";
300*ee44dd6cSjmmv     wend.flush();
301*ee44dd6cSjmmv     std::string tmp;
302*ee44dd6cSjmmv     rend >> tmp;
303*ee44dd6cSjmmv     ATF_REQUIRE_EQ(tmp, "1Test");
304*ee44dd6cSjmmv     rend >> tmp;
305*ee44dd6cSjmmv     ATF_REQUIRE_EQ(tmp, "1message");
306*ee44dd6cSjmmv }
307*ee44dd6cSjmmv 
308*ee44dd6cSjmmv // ------------------------------------------------------------------------
309*ee44dd6cSjmmv // Tests for the "muxer" class.
310*ee44dd6cSjmmv // ------------------------------------------------------------------------
311*ee44dd6cSjmmv 
312*ee44dd6cSjmmv namespace {
313*ee44dd6cSjmmv 
314*ee44dd6cSjmmv static void
check_stream(std::ostream & os)315*ee44dd6cSjmmv check_stream(std::ostream& os)
316*ee44dd6cSjmmv {
317*ee44dd6cSjmmv     // If we receive a signal while writing to the stream, the bad bit gets set.
318*ee44dd6cSjmmv     // Things seem to behave fine afterwards if we clear such error condition.
319*ee44dd6cSjmmv     // However, I'm not sure if it's safe to query errno at this point.
320*ee44dd6cSjmmv     ATF_REQUIRE(os.good() || (os.bad() && errno == EINTR));
321*ee44dd6cSjmmv     os.clear();
322*ee44dd6cSjmmv }
323*ee44dd6cSjmmv 
324*ee44dd6cSjmmv class mock_muxer : public tools::io::muxer {
line_callback(const size_t index,const std::string & line)325*ee44dd6cSjmmv     void line_callback(const size_t index, const std::string& line)
326*ee44dd6cSjmmv     {
327*ee44dd6cSjmmv         // The following should be enabled but causes the output to be so big
328*ee44dd6cSjmmv         // that it is annoying.  Reenable at some point if we make atf store
329*ee44dd6cSjmmv         // the output of the test cases in some other way (e.g. only if a test
330*ee44dd6cSjmmv         // failes), because this message is the only help in seeing how the
331*ee44dd6cSjmmv         // test fails.
332*ee44dd6cSjmmv         //std::cout << "line_callback(" << index << ", " << line << ")\n";
333*ee44dd6cSjmmv         check_stream(std::cout);
334*ee44dd6cSjmmv         switch (index) {
335*ee44dd6cSjmmv         case 0: lines0.push_back(line); break;
336*ee44dd6cSjmmv         case 1: lines1.push_back(line); break;
337*ee44dd6cSjmmv         default: ATF_REQUIRE(false);
338*ee44dd6cSjmmv         }
339*ee44dd6cSjmmv     }
340*ee44dd6cSjmmv 
341*ee44dd6cSjmmv public:
mock_muxer(const int * fds,const size_t nfds,const size_t bufsize)342*ee44dd6cSjmmv     mock_muxer(const int* fds, const size_t nfds, const size_t bufsize) :
343*ee44dd6cSjmmv         muxer(fds, nfds, bufsize) {}
344*ee44dd6cSjmmv 
345*ee44dd6cSjmmv     std::vector< std::string > lines0;
346*ee44dd6cSjmmv     std::vector< std::string > lines1;
347*ee44dd6cSjmmv };
348*ee44dd6cSjmmv 
349*ee44dd6cSjmmv static bool child_finished = false;
sigchld_handler(int signo)350*ee44dd6cSjmmv static void sigchld_handler(int signo)
351*ee44dd6cSjmmv {
352*ee44dd6cSjmmv     assert(signo == SIGCHLD);
353*ee44dd6cSjmmv     child_finished = true;
354*ee44dd6cSjmmv }
355*ee44dd6cSjmmv 
356*ee44dd6cSjmmv static void
child_printer(const int pipeout[2],const int pipeerr[2],const size_t iterations)357*ee44dd6cSjmmv child_printer(const int pipeout[2], const int pipeerr[2],
358*ee44dd6cSjmmv               const size_t iterations)
359*ee44dd6cSjmmv {
360*ee44dd6cSjmmv     ::close(pipeout[0]);
361*ee44dd6cSjmmv     ::close(pipeerr[0]);
362*ee44dd6cSjmmv     ATF_REQUIRE(::dup2(pipeout[1], STDOUT_FILENO) != -1);
363*ee44dd6cSjmmv     ATF_REQUIRE(::dup2(pipeerr[1], STDERR_FILENO) != -1);
364*ee44dd6cSjmmv     ::close(pipeout[1]);
365*ee44dd6cSjmmv     ::close(pipeerr[1]);
366*ee44dd6cSjmmv 
367*ee44dd6cSjmmv     for (size_t i = 0; i < iterations; i++) {
368*ee44dd6cSjmmv         std::cout << "stdout " << i << "\n";
369*ee44dd6cSjmmv         std::cerr << "stderr " << i << "\n";
370*ee44dd6cSjmmv     }
371*ee44dd6cSjmmv 
372*ee44dd6cSjmmv     std::cout << "stdout eof\n";
373*ee44dd6cSjmmv     std::cerr << "stderr eof\n";
374*ee44dd6cSjmmv     std::exit(EXIT_SUCCESS);
375*ee44dd6cSjmmv }
376*ee44dd6cSjmmv 
377*ee44dd6cSjmmv static void
muxer_test(const size_t bufsize,const size_t iterations)378*ee44dd6cSjmmv muxer_test(const size_t bufsize, const size_t iterations)
379*ee44dd6cSjmmv {
380*ee44dd6cSjmmv     int pipeout[2], pipeerr[2];
381*ee44dd6cSjmmv     ATF_REQUIRE(pipe(pipeout) != -1);
382*ee44dd6cSjmmv     ATF_REQUIRE(pipe(pipeerr) != -1);
383*ee44dd6cSjmmv 
384*ee44dd6cSjmmv     tools::signals::signal_programmer sigchld(SIGCHLD, sigchld_handler);
385*ee44dd6cSjmmv 
386*ee44dd6cSjmmv     std::cout.flush();
387*ee44dd6cSjmmv     std::cerr.flush();
388*ee44dd6cSjmmv 
389*ee44dd6cSjmmv     pid_t pid = ::fork();
390*ee44dd6cSjmmv     ATF_REQUIRE(pid != -1);
391*ee44dd6cSjmmv     if (pid == 0) {
392*ee44dd6cSjmmv         sigchld.unprogram();
393*ee44dd6cSjmmv         child_printer(pipeout, pipeerr, iterations);
394*ee44dd6cSjmmv         std::abort();
395*ee44dd6cSjmmv     }
396*ee44dd6cSjmmv     ::close(pipeout[1]);
397*ee44dd6cSjmmv     ::close(pipeerr[1]);
398*ee44dd6cSjmmv 
399*ee44dd6cSjmmv     int fds[2] = {pipeout[0], pipeerr[0]};
400*ee44dd6cSjmmv     mock_muxer mux(fds, 2, bufsize);
401*ee44dd6cSjmmv 
402*ee44dd6cSjmmv     mux.mux(child_finished);
403*ee44dd6cSjmmv     check_stream(std::cout);
404*ee44dd6cSjmmv     std::cout << "mux done\n";
405*ee44dd6cSjmmv 
406*ee44dd6cSjmmv     mux.flush();
407*ee44dd6cSjmmv     std::cout << "flush done\n";
408*ee44dd6cSjmmv     check_stream(std::cout);
409*ee44dd6cSjmmv 
410*ee44dd6cSjmmv     sigchld.unprogram();
411*ee44dd6cSjmmv     int status;
412*ee44dd6cSjmmv     ATF_REQUIRE(::waitpid(pid, &status, 0) != -1);
413*ee44dd6cSjmmv     ATF_REQUIRE(WIFEXITED(status));
414*ee44dd6cSjmmv     ATF_REQUIRE(WEXITSTATUS(status) == EXIT_SUCCESS);
415*ee44dd6cSjmmv 
416*ee44dd6cSjmmv     ATF_REQUIRE(std::cout.good());
417*ee44dd6cSjmmv     ATF_REQUIRE(std::cerr.good());
418*ee44dd6cSjmmv     for (size_t i = 0; i < iterations; i++) {
419*ee44dd6cSjmmv         std::ostringstream exp0, exp1;
420*ee44dd6cSjmmv         exp0 << "stdout " << i;
421*ee44dd6cSjmmv         exp1 << "stderr " << i;
422*ee44dd6cSjmmv 
423*ee44dd6cSjmmv         ATF_REQUIRE(mux.lines0.size() > i);
424*ee44dd6cSjmmv         ATF_REQUIRE_EQ(exp0.str(), mux.lines0[i]);
425*ee44dd6cSjmmv         ATF_REQUIRE(mux.lines1.size() > i);
426*ee44dd6cSjmmv         ATF_REQUIRE_EQ(exp1.str(), mux.lines1[i]);
427*ee44dd6cSjmmv     }
428*ee44dd6cSjmmv     ATF_REQUIRE_EQ("stdout eof", mux.lines0[iterations]);
429*ee44dd6cSjmmv     ATF_REQUIRE_EQ("stderr eof", mux.lines1[iterations]);
430*ee44dd6cSjmmv     std::cout << "all done\n";
431*ee44dd6cSjmmv }
432*ee44dd6cSjmmv 
433*ee44dd6cSjmmv } // anonymous namespace
434*ee44dd6cSjmmv 
435*ee44dd6cSjmmv ATF_TEST_CASE_WITHOUT_HEAD(muxer_small_buffer);
ATF_TEST_CASE_BODY(muxer_small_buffer)436*ee44dd6cSjmmv ATF_TEST_CASE_BODY(muxer_small_buffer)
437*ee44dd6cSjmmv {
438*ee44dd6cSjmmv     muxer_test(4, 20000);
439*ee44dd6cSjmmv }
440*ee44dd6cSjmmv 
441*ee44dd6cSjmmv ATF_TEST_CASE_WITHOUT_HEAD(muxer_large_buffer);
ATF_TEST_CASE_BODY(muxer_large_buffer)442*ee44dd6cSjmmv ATF_TEST_CASE_BODY(muxer_large_buffer)
443*ee44dd6cSjmmv {
444*ee44dd6cSjmmv     muxer_test(1024, 50000);
445*ee44dd6cSjmmv }
446*ee44dd6cSjmmv 
447*ee44dd6cSjmmv // ------------------------------------------------------------------------
448*ee44dd6cSjmmv // Main.
449*ee44dd6cSjmmv // ------------------------------------------------------------------------
450*ee44dd6cSjmmv 
ATF_INIT_TEST_CASES(tcs)451*ee44dd6cSjmmv ATF_INIT_TEST_CASES(tcs)
452*ee44dd6cSjmmv {
453*ee44dd6cSjmmv     // Add the tests for the "file_handle" class.
454*ee44dd6cSjmmv     ATF_ADD_TEST_CASE(tcs, file_handle_ctor);
455*ee44dd6cSjmmv     ATF_ADD_TEST_CASE(tcs, file_handle_copy);
456*ee44dd6cSjmmv     ATF_ADD_TEST_CASE(tcs, file_handle_get);
457*ee44dd6cSjmmv     ATF_ADD_TEST_CASE(tcs, file_handle_posix_remap);
458*ee44dd6cSjmmv 
459*ee44dd6cSjmmv     // Add the tests for the "systembuf" class.
460*ee44dd6cSjmmv     ATF_ADD_TEST_CASE(tcs, systembuf_short_read);
461*ee44dd6cSjmmv     ATF_ADD_TEST_CASE(tcs, systembuf_long_read);
462*ee44dd6cSjmmv     ATF_ADD_TEST_CASE(tcs, systembuf_short_write);
463*ee44dd6cSjmmv     ATF_ADD_TEST_CASE(tcs, systembuf_long_write);
464*ee44dd6cSjmmv 
465*ee44dd6cSjmmv     // Add the tests for the "pistream" class.
466*ee44dd6cSjmmv     ATF_ADD_TEST_CASE(tcs, pistream);
467*ee44dd6cSjmmv 
468*ee44dd6cSjmmv     // Add the tests for the "muxer" class.
469*ee44dd6cSjmmv     ATF_ADD_TEST_CASE(tcs, muxer_small_buffer);
470*ee44dd6cSjmmv     ATF_ADD_TEST_CASE(tcs, muxer_large_buffer);
471*ee44dd6cSjmmv }
472