1/* 2 * Copyright (c) 2009 Mark Heily <mark@heily.com> 3 * 4 * Permission to use, copy, modify, and distribute this software for any 5 * purpose with or without fee is hereby granted, provided that the above 6 * copyright notice and this permission notice appear in all copies. 7 * 8 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 9 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 10 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 11 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 12 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 13 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 14 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 15 */ 16 17#include <sys/types.h> 18#include <poll.h> 19 20#include "common.h" 21 22struct unit_test { 23 const char *ut_name; 24 int ut_enabled; 25 void (*ut_func)(int); 26}; 27 28/* 29 * Test the method for detecting when one end of a socketpair 30 * has been closed. This technique is used in kqueue_validate() 31 */ 32static void 33test_peer_close_detection(void) 34{ 35 int sockfd[2]; 36 char buf[1]; 37 struct pollfd pfd; 38 39 if (socketpair(AF_UNIX, SOCK_STREAM, 0, sockfd) < 0) 40 die("socketpair"); 41 42 pfd.fd = sockfd[0]; 43 pfd.events = POLLIN | POLLHUP; 44 pfd.revents = 0; 45 46 if (poll(&pfd, 1, 0) > 0) 47 die("unexpected data"); 48 49 if (close(sockfd[1]) < 0) 50 die("close"); 51 52 if (poll(&pfd, 1, 0) > 0) { 53 if (recv(sockfd[0], buf, sizeof(buf), MSG_PEEK | MSG_DONTWAIT) != 0) 54 die("failed to detect peer shutdown"); 55 } 56} 57 58void 59test_kqueue(void) 60{ 61 int kqfd; 62 63 if ((kqfd = kqueue()) < 0) 64 die("kqueue()"); 65 test_no_kevents(kqfd); 66 if (close(kqfd) < 0) 67 die("close()"); 68} 69 70void 71test_kevent(void) 72{ 73 struct kevent kev; 74 75 memset(&kev, 0, sizeof(kev)); 76 77 /* Provide an invalid kqueue descriptor */ 78 if (kevent(-1, &kev, 1, NULL, 0, NULL) == 0) 79 die("invalid kq parameter"); 80} 81 82 83void 84test_ev_receipt(void) 85{ 86 int kq; 87 struct kevent kev; 88 89 if ((kq = kqueue()) < 0) 90 die("kqueue()"); 91#if HAVE_EV_RECEIPT 92 93 EV_SET(&kev, SIGUSR2, EVFILT_SIGNAL, EV_ADD | EV_RECEIPT, 0, 0, NULL); 94 if (kevent(kq, &kev, 1, &kev, 1, NULL) < 0) 95 die("kevent"); 96 97 /* TODO: check the receipt */ 98 99 close(kq); 100#else 101 memset(&kev, 0, sizeof(kev)); 102 puts("Skipped -- EV_RECEIPT is not available"); 103#endif 104} 105 106int 107main(int argc, char **argv) 108{ 109 struct unit_test tests[] = { 110 { "socket", 1, test_evfilt_read }, 111 { "signal", 1, test_evfilt_signal }, 112#if FIXME 113 { "proc", 1, test_evfilt_proc }, 114#endif 115 { "vnode", 1, test_evfilt_vnode }, 116 { "timer", 1, test_evfilt_timer }, 117#if HAVE_EVFILT_USER 118 { "user", 1, test_evfilt_user }, 119#endif 120 { NULL, 0, NULL }, 121 }; 122 struct unit_test *test; 123 char *arg; 124 int match, kqfd; 125 126 /* If specific tests are requested, disable all tests by default */ 127 if (argc > 1) { 128 for (test = &tests[0]; test->ut_name != NULL; test++) { 129 test->ut_enabled = 0; 130 } 131 } 132 133 while (argc > 1) { 134 match = 0; 135 arg = argv[1]; 136 for (test = &tests[0]; test->ut_name != NULL; test++) { 137 if (strcmp(arg, test->ut_name) == 0) { 138 test->ut_enabled = 1; 139 match = 1; 140 break; 141 } 142 } 143 if (!match) { 144 printf("ERROR: invalid option: %s\n", arg); 145 exit(1); 146 } else { 147 printf("enabled test: %s\n", arg); 148 } 149 argv++; 150 argc--; 151 } 152 153 testing_begin(); 154 155 test(peer_close_detection); 156 157 test(kqueue); 158 test(kevent); 159 160 if ((kqfd = kqueue()) < 0) 161 die("kqueue()"); 162 163 for (test = &tests[0]; test->ut_name != NULL; test++) { 164 if (test->ut_enabled) 165 test->ut_func(kqfd); 166 } 167 168 test(ev_receipt); 169 170 testing_end(); 171 172 return (0); 173} 174