2 * Copyright (c) 2008-2012 Zmanda, Inc. All Rights Reserved.
4 * This program is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU General Public License
6 * as published by the Free Software Foundation; either version 2
7 * of the License, or (at your option) any later version.
9 * This program is distributed in the hope that it will be useful, but
10 * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
11 * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
14 * You should have received a copy of the GNU General Public License along
15 * with this program; if not, write to the Free Software Foundation, Inc.,
16 * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
18 * Contact information: Zmanda Inc, 465 S. Mathilda Ave., Suite 300
19 * Sunnyvale, CA 94085, USA, or: http://www.zmanda.com
21 * Author: Dustin J. Mitchell <dustin@zmanda.com>
25 #include "testutils.h"
28 /* a random global variable to flag that some function has been called */
31 /* file descriptor under EV_READFD or EV_WRITEFD */
34 /* and some easy access to the event handles for callbacks */
35 static event_handle_t *hdl[10];
41 /* A common event callback that just decrements 'global', and frees
42 * hdl[0] if global reaches zero.
45 test_decrement_cb(void *up G_GNUC_UNUSED)
48 tu_dbg("Decrement global to %d\n", global);
50 tu_dbg("Release event\n");
51 event_release(hdl[0]);
60 * Test that EV_TIME events fire, repeatedly.
66 hdl[0] = event_register(1, EV_TIME, test_decrement_cb, NULL);
68 /* Block waiting for the event to fire. The event itself eventually
69 * unregisters itself, causing the event_loop to finish */
76 * Test that nonblocking waits don't block.
81 global = 1; /* the callback should not be triggered, so this should stay 1 */
82 hdl[0] = event_register(1, EV_TIME, test_decrement_cb, NULL);
84 event_loop(1); /* non-blocking */
90 * Test that EV_WAIT events fire when event_wakeup is called, without waiting for
91 * another iteration of the event loop. Security API depends on callbacks occuring
98 hdl[0] = event_register(4422, EV_WAIT, test_decrement_cb, NULL);
100 if (global != 2) return FALSE;
102 if (global != 1) return FALSE;
104 if (global != 0) return FALSE;
105 event_wakeup(4422); /* the handler has been removed, but this is not an error */
106 if (global != 0) return FALSE;
108 /* queue should now be empty, so this won't block */
115 * Test that EV_WAIT events with the same ID added during an EV_WAIT callback are not
116 * called back immediately, but wait for a subsequent wakeup. Security API depends on
117 * this behavior. This is a pathological test :)
120 test_ev_wait_2_cb(void *up G_GNUC_UNUSED)
123 tu_dbg("Decrement global to %d\n", global);
126 tu_dbg("release EV_WAIT event\n");
127 event_release(hdl[0]);
130 tu_dbg("register new EV_WAIT event with same ID\n");
131 hdl[0] = event_register(84, EV_WAIT, test_ev_wait_2_cb, NULL);
139 hdl[0] = event_register(84, EV_WAIT, test_ev_wait_2_cb, NULL);
141 /* Each wakeup should only invoke the callback *once* */
142 if (global != 2) return FALSE;
144 if (global != 1) return FALSE;
146 if (global != 0) return FALSE;
147 event_wakeup(84); /* the handler has been removed, but this is not an error */
148 if (global != 0) return FALSE;
154 * Test that event_wait correctly waits for a EV_TIME event to fire, even when
155 * other events are running. */
157 test_event_wait_cb(void *up G_GNUC_UNUSED)
159 int *cb_fired = (int *)up;
162 /* immediately unregister ourselves */
163 tu_dbg("test_event_wait_cb called\n");
164 event_release(hdl[1]);
168 test_event_wait(void)
173 /* this one serves as a "decoy", running in the background while we wait
174 * for test_event_wait_cb */
175 hdl[0] = event_register(1, EV_TIME, test_decrement_cb, NULL);
177 /* this is our own callback */
178 hdl[1] = event_register(2, EV_TIME, test_event_wait_cb, (void *)&cb_fired);
180 /* wait until our own callback fires */
183 /* at this point, test_decrement_cb should have fired once or twice, but not
186 tu_dbg("global is already zero!\n");
190 /* and our own callback should have fired */
192 tu_dbg("test_event_wait_cb didn't fire\n");
200 * Test that event_wait correctly waits for a EV_WAIT event to be released, not
201 * fired, even when other events are running. */
203 test_event_wait_2_cb(void *up)
205 int *wakeups_remaining = (int *)up;
206 tu_dbg("test_event_wait_2_cb called\n");
208 if (--(*wakeups_remaining) == 0) {
209 /* unregister ourselves if we've awakened enough times */
210 event_release(hdl[2]);
216 test_event_wait_2_wakeup_cb(void *up G_GNUC_UNUSED)
218 tu_dbg("test_event_wait_2_wakeup_cb called\n");
220 /* wake up the EV_WAIT event */
225 test_event_wait_2(void)
227 int wakeups_remaining = 2;
230 /* this one serves as a "decoy", running in the background while we wait
231 * for test_event_wait_2_cb */
232 hdl[0] = event_register(1, EV_TIME, test_decrement_cb, NULL);
234 /* This one repeatedly calls event_wakeup for the EV_WAIT event */
235 hdl[1] = event_register(1, EV_TIME, test_event_wait_2_wakeup_cb, NULL);
237 /* this is our own callback */
238 hdl[2] = event_register(9876, EV_WAIT, test_event_wait_2_cb, (void *)&wakeups_remaining);
240 /* wait until the EV_WAIT is *released*, not just fired. */
243 /* at this point, test_decrement_cb should have fired twice, but not
246 tu_dbg("global is already zero!\n");
250 /* and our own callback should have fired twice, not just once */
251 if (wakeups_remaining != 0) {
252 tu_dbg("test_event_wait_2_cb didn't fire twice\n");
260 * Test that EV_READFD is triggered correctly when there's data available
261 * for reading. The source of read events is a spawned child which writes
262 * lots of data to a pipe, in hopes of overflowing the pipe buffer.
265 test_ev_readfd_cb(void *up G_GNUC_UNUSED)
270 /* read from the fd until we're out of bytes */
271 tu_dbg("reader: callback executing\n");
272 len = read(cb_fd, buf, sizeof(buf));
274 tu_dbg("reader: callback returning\n");
275 } else if (len < 0) {
276 tu_dbg("reader: read() returned %d: %s\n", len, strerror(errno));
277 /* do we need to handle e.g., EAGAIN here? */
279 tu_dbg("reader: read %d bytes\n", len);
281 /* release this event if we've read all of the available bytes */
284 event_release(hdl[0]);
290 test_ev_readfd_writer(int fd, size_t count)
295 for (i = 0; i < sizeof(buf); i++) {
302 len = write(fd, buf, min(sizeof(buf), count));
303 tu_dbg("writer wrote %d bytes\n", len);
310 #define TEST_EV_READFD_SIZE (1024*1024)
323 /* fork off the writer */
324 switch (writer_pid = fork()) {
327 test_ev_readfd_writer(p[1], TEST_EV_READFD_SIZE);
335 default: /* parent */
339 /* set up a EV_READFD on the read end of the pipe */
341 fcntl(cb_fd, F_SETFL, O_NONBLOCK);
343 global = TEST_EV_READFD_SIZE;
344 hdl[0] = event_register(p[0], EV_READFD, test_ev_readfd_cb, NULL);
349 tu_dbg("waiting for writer to die..\n");
350 waitpid(writer_pid, NULL, 0);
353 tu_dbg("%d bytes remain unread..\n", global);
361 * Test the combination of an EV_TIME and an EV_READFD to peform a
362 * timeout-protected read that times out.
365 test_read_timeout_slow_writer(int fd)
367 char buf[] = "OH NO!";
369 /* this should exceed the timeout, which is 1s */
372 if (write(fd, buf, strlen(buf)+1) == -1) {
379 test_read_timeout_cb(void *up G_GNUC_UNUSED)
381 tu_dbg("read timed out (this is supposed to happen)\n");
382 global = 1234; /* sentinel value */
384 /* free up all of the events so that event_loop returns */
385 event_release(hdl[0]);
386 event_release(hdl[1]);
390 test_read_timeout(void)
400 /* fork off the writer */
401 switch (writer_pid = fork()) {
404 test_read_timeout_slow_writer(p[1]);
412 default: /* parent */
416 /* set up a EV_READFD on the read end of the pipe */
418 fcntl(cb_fd, F_SETFL, O_NONBLOCK);
420 hdl[0] = event_register(p[0], EV_READFD, test_ev_readfd_cb, NULL);
422 /* and set up a timeout */
423 global = 0; /* timeout_cb will set this to 1234 */
424 hdl[1] = event_register(1, EV_TIME, test_read_timeout_cb, NULL);
429 /* see if we got the sentinel indicating the timeout fired */
437 * Test that EV_WRITEFD is triggered correctly when there's buffer space to
442 test_ev_writefd_cb(void *up G_GNUC_UNUSED)
448 /* initialize the buffer to something worthwhile */
449 for (i = 0; i < sizeof(buf); i++) {
453 /* write some bytes, but no more than global */
454 tu_dbg("test_ev_writefd_cb called\n");
456 len = write(cb_fd, buf, min((size_t)global, sizeof(buf)));
458 tu_dbg("test_ev_writefd_cb: write() returned %d\n", len);
460 } else if (len == 0) {
461 /* do we need to handle EAGAIN, etc. here? */
462 tu_dbg("test_ev_writefd_cb done\n");
465 tu_dbg(" write() wrote %d bytes\n", len);
469 event_release(hdl[0]);
476 test_ev_writefd_consumer(int fd, size_t count)
482 tu_dbg("reader: calling read(%d)\n", (int)sizeof(buf));
483 len = read(fd, buf, sizeof(buf));
485 /* exit on a read error or EOF */
488 tu_dbg("reader: read() returned %d bytes\n", len);
494 #define TEST_EV_WRITEFD_SIZE (1024*1024)
497 test_ev_writefd(void)
507 /* fork off the reader */
508 switch (reader_pid = fork()) {
511 test_ev_writefd_consumer(p[0], TEST_EV_WRITEFD_SIZE);
519 default: /* parent */
523 /* set up a EV_WRITEFD on the write end of the pipe */
525 fcntl(cb_fd, F_SETFL, O_NONBLOCK);
526 global = TEST_EV_WRITEFD_SIZE;
528 hdl[0] = event_register(p[1], EV_WRITEFD, test_ev_writefd_cb, NULL);
533 tu_dbg("waiting for reader to die..\n");
534 waitpid(reader_pid, NULL, 0);
536 /* and see what we got */
538 tu_dbg("writes did not complete\n");
546 * Test that a child_watch_source works correctly.
549 static gint test_child_watch_result = 0;
550 static GMainLoop *test_child_watch_main_loop = NULL;
553 test_child_watch_callback(
558 static int count = 0;
559 gint expected_pid = GPOINTER_TO_INT(data);
561 if (pid != expected_pid
562 || !WIFEXITED(status)
563 || WEXITSTATUS(status) != 13)
564 test_child_watch_result = FALSE;
566 test_child_watch_result = TRUE;
570 g_main_loop_quit(test_child_watch_main_loop);
574 test_child_watch_source(void)
579 /* fork off the child we want to watch die */
580 switch (pid = fork()) {
589 default: /* parent */
593 /* set up a child watch */
594 src = new_child_watch_source(pid);
595 g_source_set_callback(src, (GSourceFunc)test_child_watch_callback,
596 GINT_TO_POINTER(pid), NULL);
597 g_source_attach(src, NULL);
600 switch (pid2 = fork()) {
609 default: /* parent */
614 /* set up a child watch */
615 src2 = new_child_watch_source(pid2);
616 g_source_set_callback(src2, (GSourceFunc)test_child_watch_callback,
617 GINT_TO_POINTER(pid2), NULL);
618 g_source_attach(src2, NULL);
619 g_source_unref(src2);
622 test_child_watch_main_loop = g_main_loop_new(NULL, 1);
623 g_main_loop_run(test_child_watch_main_loop);
625 return test_child_watch_result;
633 main(int argc, char **argv)
635 static TestUtilsTest tests[] = {
636 TU_TEST(test_ev_time, 90),
637 TU_TEST(test_ev_wait, 90),
638 TU_TEST(test_ev_wait_2, 90),
639 TU_TEST(test_ev_readfd, 120), /* runs slowly on old kernels */
640 TU_TEST(test_ev_writefd, 90),
641 TU_TEST(test_event_wait, 90),
642 TU_TEST(test_event_wait_2, 90),
643 TU_TEST(test_nonblock, 90),
644 TU_TEST(test_read_timeout, 90),
645 TU_TEST(test_child_watch_source, 90),
646 /* fdsource is used by ev_readfd/ev_writefd, and is sufficiently tested there */
650 return testutils_run_tests(argc, argv, tests);