Home | History | Annotate | Line # | Download | only in tools
      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 <cassert>
     39 #include <cerrno>
     40 #include <cstddef>
     41 #include <cstdlib>
     42 #include <cstring>
     43 #include <fstream>
     44 #include <iostream>
     45 #include <istream>
     46 #include <ostream>
     47 
     48 #include <atf-c++.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 tools::io::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 tools::io::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 tools::io::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 tools::io::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 tools::io::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 tools::io::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 tools::io::file_handle;
    286     using tools::io::pistream;
    287     using tools::io::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 tools::io::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     assert(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     tools::signals::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         std::abort();
    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 }
    472