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