2 * Copyright (c) 2008 Zmanda Inc. All Rights Reserved.
4 * This program is free software; you can redistribute it and/or modify it
5 * under the terms of the GNU General Public License version 2 as published
6 * by the Free Software Foundation.
8 * This program is distributed in the hope that it will be useful, but
9 * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
10 * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
13 * You should have received a copy of the GNU General Public License along
14 * with this program; if not, write to the Free Software Foundation, Inc.,
15 * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
17 * Contact information: Zmanda Inc, 465 N Mathlida Ave, Suite 300
18 * Sunnyvale, CA 94085, USA, or: http://www.zmanda.com
20 * Author: Dustin J. Mitchell <dustin@zmanda.com>
24 #include "testutils.h"
27 /* a random global variable to flag that some function has been called */
30 /* file descriptor under EV_READFD or EV_WRITEFD */
33 /* and some easy access to the event handles for callbacks */
34 static event_handle_t *hdl[10];
40 /* A common event callback that just decrements 'global', and frees
41 * hdl[0] if global reaches zero.
44 test_decrement_cb(void *up G_GNUC_UNUSED)
47 tu_dbg("Decrement global to %d\n", global);
49 tu_dbg("Release event\n");
50 event_release(hdl[0]);
59 * Test that EV_TIME events fire, repeatedly.
65 hdl[0] = event_register(1, EV_TIME, test_decrement_cb, NULL);
67 /* Block waiting for the event to fire. The event itself eventually
68 * unregisters itself, causing the event_loop to finish */
75 * Test that nonblocking waits don't block.
80 global = 1; /* the callback should not be triggered, so this should stay 1 */
81 hdl[0] = event_register(1, EV_TIME, test_decrement_cb, NULL);
83 event_loop(1); /* non-blocking */
89 * Test that EV_WAIT events fire when event_wakeup is called, without waiting for
90 * another iteration of the event loop. Security API depends on callbacks occuring
97 hdl[0] = event_register(4422, EV_WAIT, test_decrement_cb, NULL);
99 if (global != 2) return 0;
101 if (global != 1) return 0;
103 if (global != 0) return 0;
104 event_wakeup(4422); /* the handler has been removed, but this is not an error */
105 if (global != 0) return 0;
107 /* queue should now be empty, so this won't block */
114 * Test that EV_WAIT events with the same ID added during an EV_WAIT callback are not
115 * called back immediately, but wait for a subsequent wakeup. Security API depends on
116 * this behavior. This is a pathological test :)
119 test_ev_wait_2_cb(void *up G_GNUC_UNUSED)
122 tu_dbg("Decrement global to %d\n", global);
125 tu_dbg("release EV_WAIT event\n");
126 event_release(hdl[0]);
129 tu_dbg("register new EV_WAIT event with same ID\n");
130 hdl[0] = event_register(84, EV_WAIT, test_ev_wait_2_cb, NULL);
138 hdl[0] = event_register(84, EV_WAIT, test_ev_wait_2_cb, NULL);
140 /* Each wakeup should only invoke the callback *once* */
141 if (global != 2) return 0;
143 if (global != 1) return 0;
145 if (global != 0) return 0;
146 event_wakeup(84); /* the handler has been removed, but this is not an error */
147 if (global != 0) return 0;
153 * Test that event_wait correctly waits for a EV_TIME event to fire, even when
154 * other events are running. */
156 test_event_wait_cb(void *up G_GNUC_UNUSED)
158 int *cb_fired = (int *)up;
161 /* immediately unregister ourselves */
162 tu_dbg("test_event_wait_cb called\n");
163 event_release(hdl[1]);
167 test_event_wait(void)
172 /* this one serves as a "decoy", running in the background while we wait
173 * for test_event_wait_cb */
174 hdl[0] = event_register(1, EV_TIME, test_decrement_cb, NULL);
176 /* this is our own callback */
177 hdl[1] = event_register(2, EV_TIME, test_event_wait_cb, (void *)&cb_fired);
179 /* wait until our own callback fires */
182 /* at this point, test_decrement_cb should have fired once or twice, but not
185 tu_dbg("global is already zero!\n");
189 /* and our own callback should have fired */
191 tu_dbg("test_event_wait_cb didn't fire\n");
199 * Test that event_wait correctly waits for a EV_WAIT event to be released, not
200 * fired, even when other events are running. */
202 test_event_wait_2_cb(void *up)
204 int *wakeups_remaining = (int *)up;
205 tu_dbg("test_event_wait_2_cb called\n");
207 if (--(*wakeups_remaining) == 0) {
208 /* unregister ourselves if we've awakened enough times */
209 event_release(hdl[2]);
215 test_event_wait_2_wakeup_cb(void *up G_GNUC_UNUSED)
217 tu_dbg("test_event_wait_2_wakeup_cb called\n");
219 /* wake up the EV_WAIT event */
224 test_event_wait_2(void)
226 int wakeups_remaining = 2;
229 /* this one serves as a "decoy", running in the background while we wait
230 * for test_event_wait_2_cb */
231 hdl[0] = event_register(1, EV_TIME, test_decrement_cb, NULL);
233 /* This one repeatedly calls event_wakeup for the EV_WAIT event */
234 hdl[1] = event_register(1, EV_TIME, test_event_wait_2_wakeup_cb, NULL);
236 /* this is our own callback */
237 hdl[2] = event_register(9876, EV_WAIT, test_event_wait_2_cb, (void *)&wakeups_remaining);
239 /* wait until the EV_WAIT is *released*, not just fired. */
242 /* at this point, test_decrement_cb should have fired twice, but not
245 tu_dbg("global is already zero!\n");
249 /* and our own callback should have fired twice, not just once */
250 if (wakeups_remaining != 0) {
251 tu_dbg("test_event_wait_2_cb didn't fire twice\n");
259 * Test that EV_READFD is triggered correctly when there's data available
260 * for reading. The source of read events is a spawned child which writes
261 * lots of data to a pipe, in hopes of overflowing the pipe buffer.
264 test_ev_readfd_cb(void *up G_GNUC_UNUSED)
269 /* read from the fd until we're out of bytes */
270 tu_dbg("reader: callback executing\n");
271 len = read(cb_fd, buf, sizeof(buf));
273 tu_dbg("reader: callback returning\n");
274 } else if (len < 0) {
275 tu_dbg("reader: read() returned %d: %s\n", len, strerror(errno));
276 /* do we need to handle e.g., EAGAIN here? */
278 tu_dbg("reader: read %d bytes\n", len);
280 /* release this event if we've read all of the available bytes */
283 event_release(hdl[0]);
289 test_ev_readfd_writer(int fd, size_t count)
294 for (i = 0; i < sizeof(buf); i++) {
301 len = write(fd, buf, min(sizeof(buf), count));
302 tu_dbg("writer wrote %d bytes\n", len);
309 #define TEST_EV_READFD_SIZE (1024*1024)
322 /* fork off the writer */
323 switch (writer_pid = fork()) {
326 test_ev_readfd_writer(p[1], TEST_EV_READFD_SIZE);
334 default: /* parent */
338 /* set up a EV_READFD on the read end of the pipe */
340 fcntl(cb_fd, F_SETFL, O_NONBLOCK);
342 global = TEST_EV_READFD_SIZE;
343 hdl[0] = event_register(p[0], EV_READFD, test_ev_readfd_cb, NULL);
348 tu_dbg("waiting for writer to die..\n");
349 waitpid(writer_pid, NULL, 0);
352 tu_dbg("%d bytes remain unread..\n", global);
360 * Test the combination of an EV_TIME and an EV_READFD to peform a
361 * timeout-protected read that times out.
364 test_read_timeout_slow_writer(int fd)
366 char buf[] = "OH NO!";
368 /* this should exceed the timeout, which is 1s */
371 if (write(fd, buf, strlen(buf)+1) == -1) {
378 test_read_timeout_cb(void *up G_GNUC_UNUSED)
380 tu_dbg("read timed out (this is supposed to happen)\n");
381 global = 1234; /* sentinel value */
383 /* free up all of the events so that event_loop returns */
384 event_release(hdl[0]);
385 event_release(hdl[1]);
389 test_read_timeout(void)
399 /* fork off the writer */
400 switch (writer_pid = fork()) {
403 test_read_timeout_slow_writer(p[1]);
411 default: /* parent */
415 /* set up a EV_READFD on the read end of the pipe */
417 fcntl(cb_fd, F_SETFL, O_NONBLOCK);
419 hdl[0] = event_register(p[0], EV_READFD, test_ev_readfd_cb, NULL);
421 /* and set up a timeout */
422 global = 0; /* timeout_cb will set this to 1234 */
423 hdl[1] = event_register(1, EV_TIME, test_read_timeout_cb, NULL);
428 /* see if we got the sentinel indicating the timeout fired */
436 * Test that EV_WRITEFD is triggered correctly when there's buffer space to
441 test_ev_writefd_cb(void *up G_GNUC_UNUSED)
447 /* initialize the buffer to something worthwhile */
448 for (i = 0; i < sizeof(buf); i++) {
452 /* write some bytes, but no more than global */
453 tu_dbg("test_ev_writefd_cb called\n");
455 len = write(cb_fd, buf, min((size_t)global, sizeof(buf)));
457 tu_dbg("test_ev_writefd_cb: write() returned %d\n", len);
459 } else if (len == 0) {
460 /* do we need to handle EAGAIN, etc. here? */
461 tu_dbg("test_ev_writefd_cb done\n");
464 tu_dbg(" write() wrote %d bytes\n", len);
468 event_release(hdl[0]);
475 test_ev_writefd_consumer(int fd, size_t count)
481 tu_dbg("reader: calling read(%d)\n", (int)sizeof(buf));
482 len = read(fd, buf, sizeof(buf));
484 /* exit on a read error or EOF */
487 tu_dbg("reader: read() returned %d bytes\n", len);
493 #define TEST_EV_WRITEFD_SIZE (1024*1024)
496 test_ev_writefd(void)
506 /* fork off the reader */
507 switch (reader_pid = fork()) {
510 test_ev_writefd_consumer(p[0], TEST_EV_WRITEFD_SIZE);
518 default: /* parent */
522 /* set up a EV_WRITEFD on the write end of the pipe */
524 fcntl(cb_fd, F_SETFL, O_NONBLOCK);
525 global = TEST_EV_WRITEFD_SIZE;
527 hdl[0] = event_register(p[1], EV_WRITEFD, test_ev_writefd_cb, NULL);
532 tu_dbg("waiting for reader to die..\n");
533 waitpid(reader_pid, NULL, 0);
535 /* and see what we got */
537 tu_dbg("writes did not complete\n");
545 * Test that a child_watch_source works correctly.
548 static gint test_child_watch_result = 0;
549 static GMainLoop *test_child_watch_main_loop = NULL;
552 test_child_watch_callback(
557 static int count = 0;
558 gint expected_pid = GPOINTER_TO_INT(data);
560 if (pid != expected_pid
561 || !WIFEXITED(status)
562 || WEXITSTATUS(status) != 13)
563 test_child_watch_result = FALSE;
565 test_child_watch_result = TRUE;
569 g_main_loop_quit(test_child_watch_main_loop);
573 test_child_watch_source(void)
578 /* fork off the child we want to watch die */
579 switch (pid = fork()) {
588 default: /* parent */
592 /* set up a child watch */
593 src = new_child_watch_source(pid);
594 g_source_set_callback(src, (GSourceFunc)test_child_watch_callback,
595 GINT_TO_POINTER(pid), NULL);
596 g_source_attach(src, NULL);
599 switch (pid2 = fork()) {
608 default: /* parent */
613 /* set up a child watch */
614 src2 = new_child_watch_source(pid2);
615 g_source_set_callback(src2, (GSourceFunc)test_child_watch_callback,
616 GINT_TO_POINTER(pid2), NULL);
617 g_source_attach(src2, NULL);
618 g_source_unref(src2);
621 test_child_watch_main_loop = g_main_loop_new(NULL, 1);
622 g_main_loop_run(test_child_watch_main_loop);
624 return test_child_watch_result;
632 main(int argc, char **argv)
634 static TestUtilsTest tests[] = {
635 TU_TEST(test_ev_time, 10),
636 TU_TEST(test_ev_wait, 10),
637 TU_TEST(test_ev_wait_2, 10),
638 TU_TEST(test_ev_readfd, 60), /* runs slowly on old kernels */
639 TU_TEST(test_ev_writefd, 60),
640 TU_TEST(test_event_wait, 10),
641 TU_TEST(test_event_wait_2, 10),
642 TU_TEST(test_nonblock, 10),
643 TU_TEST(test_read_timeout, 10),
644 TU_TEST(test_child_watch_source, 5),
645 /* fdsource is used by ev_readfd/ev_writefd, and is sufficiently tested there */
649 return testutils_run_tests(argc, argv, tests);