Home | History | Annotate | Line # | Download | only in tools
      1 //
      2 // Automated Testing Framework (atf)
      3 //
      4 // Copyright (c) 2008 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/types.h>
     32 #include <signal.h>
     33 #include <unistd.h>
     34 }
     35 
     36 #include <cerrno>
     37 #include <cstdlib>
     38 #include <iostream>
     39 
     40 #include <atf-c++.hpp>
     41 
     42 #include "exceptions.hpp"
     43 #include "process.hpp"
     44 #include "signals.hpp"
     45 
     46 // ------------------------------------------------------------------------
     47 // Auxiliary functions.
     48 // ------------------------------------------------------------------------
     49 
     50 namespace sigusr1 {
     51     static bool happened = false;
     52 
     53     static
     54     void
     55     handler(int signo __attribute__((__unused__)))
     56     {
     57         happened = true;
     58     }
     59 
     60     static
     61     void
     62     program(void)
     63     {
     64         struct sigaction sa;
     65         sa.sa_handler = handler;
     66         sigemptyset(&sa.sa_mask);
     67         sa.sa_flags = 0;
     68         if (::sigaction(SIGUSR1, &sa, NULL) == -1)
     69             throw tools::system_error("sigusr1::program",
     70                                     "sigaction(2) failed", errno);
     71     }
     72 } // namespace sigusr1
     73 
     74 namespace sigusr1_2 {
     75     static bool happened = false;
     76 
     77     static
     78     void
     79     handler(int signo __attribute__((__unused__)))
     80     {
     81         happened = true;
     82     }
     83 } // namespace sigusr1_2
     84 
     85 // ------------------------------------------------------------------------
     86 // Tests for the "signal_holder" class.
     87 // ------------------------------------------------------------------------
     88 
     89 ATF_TEST_CASE(signal_holder_preserve);
     90 ATF_TEST_CASE_HEAD(signal_holder_preserve)
     91 {
     92     set_md_var("descr", "Tests that signal_holder preserves the original "
     93                "signal handler and restores it upon destruction");
     94 }
     95 ATF_TEST_CASE_BODY(signal_holder_preserve)
     96 {
     97     using tools::signals::signal_holder;
     98 
     99     sigusr1::program();
    100 
    101     sigusr1::happened = false;
    102     ::kill(::getpid(), SIGUSR1);
    103     ATF_REQUIRE(sigusr1::happened);
    104 
    105     {
    106         signal_holder hld(SIGUSR1);
    107         ::kill(::getpid(), SIGUSR1);
    108     }
    109 
    110     sigusr1::happened = false;
    111     ::kill(::getpid(), SIGUSR1);
    112     ATF_REQUIRE(sigusr1::happened);
    113 }
    114 
    115 ATF_TEST_CASE(signal_holder_destructor);
    116 ATF_TEST_CASE_HEAD(signal_holder_destructor)
    117 {
    118     set_md_var("descr", "Tests that signal_holder processes a pending "
    119                "signal upon destruction");
    120 }
    121 ATF_TEST_CASE_BODY(signal_holder_destructor)
    122 {
    123     using tools::signals::signal_holder;
    124 
    125     sigusr1::program();
    126 
    127     sigusr1::happened = false;
    128     ::kill(::getpid(), SIGUSR1);
    129     ATF_REQUIRE(sigusr1::happened);
    130 
    131     {
    132         signal_holder hld(SIGUSR1);
    133 
    134         sigusr1::happened = false;
    135         ::kill(::getpid(), SIGUSR1);
    136         ATF_REQUIRE(!sigusr1::happened);
    137     }
    138     ATF_REQUIRE(sigusr1::happened);
    139 }
    140 
    141 ATF_TEST_CASE(signal_holder_process);
    142 ATF_TEST_CASE_HEAD(signal_holder_process)
    143 {
    144     set_md_var("descr", "Tests that signal_holder's process method works "
    145                "to process a delayed signal explicitly");
    146 }
    147 ATF_TEST_CASE_BODY(signal_holder_process)
    148 {
    149     using tools::signals::signal_holder;
    150 
    151     sigusr1::program();
    152 
    153     sigusr1::happened = false;
    154     ::kill(::getpid(), SIGUSR1);
    155     ATF_REQUIRE(sigusr1::happened);
    156 
    157     {
    158         signal_holder hld(SIGUSR1);
    159 
    160         sigusr1::happened = false;
    161         ::kill(::getpid(), SIGUSR1);
    162         ATF_REQUIRE(!sigusr1::happened);
    163 
    164         hld.process();
    165         ATF_REQUIRE(sigusr1::happened);
    166 
    167         sigusr1::happened = false;
    168     }
    169     ATF_REQUIRE(!sigusr1::happened);
    170 }
    171 
    172 // ------------------------------------------------------------------------
    173 // Tests for the "signal_programmer" class.
    174 // ------------------------------------------------------------------------
    175 
    176 ATF_TEST_CASE(signal_programmer_program);
    177 ATF_TEST_CASE_HEAD(signal_programmer_program)
    178 {
    179     set_md_var("descr", "Tests that signal_programmer correctly installs a "
    180                "handler");
    181 }
    182 ATF_TEST_CASE_BODY(signal_programmer_program)
    183 {
    184     using tools::signals::signal_programmer;
    185 
    186     signal_programmer sp(SIGUSR1, sigusr1_2::handler);
    187 
    188     sigusr1_2::happened = false;
    189     ::kill(::getpid(), SIGUSR1);
    190     ATF_REQUIRE(sigusr1_2::happened);
    191 }
    192 
    193 ATF_TEST_CASE(signal_programmer_preserve);
    194 ATF_TEST_CASE_HEAD(signal_programmer_preserve)
    195 {
    196     set_md_var("descr", "Tests that signal_programmer uninstalls the "
    197                "handler during destruction");
    198 }
    199 ATF_TEST_CASE_BODY(signal_programmer_preserve)
    200 {
    201     using tools::signals::signal_programmer;
    202 
    203     sigusr1::program();
    204     sigusr1::happened = false;
    205 
    206     {
    207         signal_programmer sp(SIGUSR1, sigusr1_2::handler);
    208 
    209         sigusr1_2::happened = false;
    210         ::kill(::getpid(), SIGUSR1);
    211         ATF_REQUIRE(sigusr1_2::happened);
    212     }
    213 
    214     ATF_REQUIRE(!sigusr1::happened);
    215     ::kill(::getpid(), SIGUSR1);
    216     ATF_REQUIRE(sigusr1::happened);
    217 }
    218 
    219 // ------------------------------------------------------------------------
    220 // Tests cases for the free functions.
    221 // ------------------------------------------------------------------------
    222 
    223 static
    224 void
    225 reset_child(void *v __attribute__((__unused__)))
    226 {
    227     sigusr1::program();
    228 
    229     sigusr1::happened = false;
    230     tools::signals::reset(SIGUSR1);
    231     kill(::getpid(), SIGUSR1);
    232 
    233     if (sigusr1::happened) {
    234         std::cerr << "Signal was not resetted correctly\n";
    235         std::abort();
    236     } else {
    237         std::exit(EXIT_SUCCESS);
    238     }
    239 }
    240 
    241 ATF_TEST_CASE(reset);
    242 ATF_TEST_CASE_HEAD(reset)
    243 {
    244     set_md_var("descr", "Tests the reset function");
    245 }
    246 ATF_TEST_CASE_BODY(reset)
    247 {
    248     tools::process::child c =
    249         tools::process::fork(reset_child, tools::process::stream_inherit(),
    250                            tools::process::stream_inherit(), NULL);
    251 
    252     const tools::process::status s = c.wait();
    253     ATF_REQUIRE(s.exited() || s.signaled());
    254     ATF_REQUIRE(!s.signaled() || s.termsig() == SIGUSR1);
    255 }
    256 
    257 // ------------------------------------------------------------------------
    258 // Main.
    259 // ------------------------------------------------------------------------
    260 
    261 ATF_INIT_TEST_CASES(tcs)
    262 {
    263     // Add the tests for the "signal_holder" class.
    264     ATF_ADD_TEST_CASE(tcs, signal_holder_preserve);
    265     ATF_ADD_TEST_CASE(tcs, signal_holder_destructor);
    266     ATF_ADD_TEST_CASE(tcs, signal_holder_process);
    267 
    268     // Add the tests for the "signal_programmer" class.
    269     ATF_ADD_TEST_CASE(tcs, signal_programmer_program);
    270     ATF_ADD_TEST_CASE(tcs, signal_programmer_preserve);
    271 
    272     // Add the test cases for the free functions.
    273     ATF_ADD_TEST_CASE(tcs, reset);
    274 }
    275