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