1 /*
2 * SysDB - t/frontend/sock_test.c
3 * Copyright (C) 2013 Sebastian 'tokkee' Harl <sh@tokkee.org>
4 * All rights reserved.
5 *
6 * Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following conditions
8 * are met:
9 * 1. Redistributions of source code must retain the above copyright
10 * notice, this list of conditions and the following disclaimer.
11 * 2. Redistributions in binary form must reproduce the above copyright
12 * notice, this list of conditions and the following disclaimer in the
13 * documentation and/or other materials provided with the distribution.
14 *
15 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
16 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
17 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
18 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR
19 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
20 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
21 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
22 * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
23 * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
24 * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
25 * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26 */
28 #include "frontend/sock.h"
29 #include "libsysdb_test.h"
31 #include <check.h>
33 #include <errno.h>
35 #include <stdio.h>
36 #include <stdlib.h>
38 #include <unistd.h>
40 #include <pthread.h>
42 #include <sys/types.h>
43 #include <sys/socket.h>
44 #include <sys/un.h>
46 /*
47 * private variables
48 */
50 static sdb_fe_socket_t *sock;
52 static void
53 setup(void)
54 {
55 sock = sdb_fe_sock_create();
56 fail_unless(sock != NULL,
57 "sdb_fe_sock_create() = NULL; expected frontend sock object");
58 } /* setup */
60 static void
61 teardown(void)
62 {
63 sdb_fe_sock_destroy(sock);
64 sock = NULL;
65 } /* teardown */
67 static void
68 sock_listen(char *tmp_file)
69 {
70 char sock_addr[strlen("unix:") + L_tmpnam + 1];
71 char *filename;
73 int check;
75 filename = tmpnam(tmp_file);
76 fail_unless(filename != NULL,
77 "INTERNAL ERROR: tmpnam() = NULL; expected: a string");
79 sprintf(sock_addr, "unix:%s", tmp_file);
80 check = sdb_fe_sock_add_listener(sock, sock_addr);
81 fail_unless(check == 0,
82 "sdb_fe_sock_add_listener(%s) = %i; expected: 0",
83 sock_addr, check);
84 } /* conn */
86 /*
87 * parallel testing
88 */
90 static void *
91 sock_handler(void *data)
92 {
93 sdb_fe_loop_t *loop = data;
94 int check;
96 check = sdb_fe_sock_listen_and_serve(sock, loop);
97 fail_unless(check == 0,
98 "sdb_fe_sock_listen_and_serve() = %i; "
99 "expected: 0 (after adding listener)", check);
100 return NULL;
101 } /* sock_handler */
103 /*
104 * tests
105 */
107 START_TEST(test_listen_and_serve)
108 {
109 sdb_fe_loop_t loop = SDB_FE_LOOP_INIT;
111 char tmp_file[L_tmpnam];
112 int check;
114 pthread_t thr;
116 int sock_fd;
117 struct sockaddr_un sa;
119 check = sdb_fe_sock_listen_and_serve(sock, &loop);
120 fail_unless(check < 0,
121 "sdb_fe_sock_listen_and_serve() = %i; "
122 "expected: <0 (before adding listeners)", check);
124 sock_listen(tmp_file);
126 loop.do_loop = 1;
127 check = pthread_create(&thr, /* attr = */ NULL, sock_handler, &loop);
128 fail_unless(check == 0,
129 "INTERNAL ERROR: pthread_create() = %i; expected: 0", check);
131 sock_fd = socket(AF_UNIX, SOCK_STREAM, 0);
132 fail_unless(sock_fd >= 0,
133 "INTERNAL ERROR: socket() = %d; expected: >= 0", sock_fd);
135 sa.sun_family = AF_UNIX;
136 strncpy(sa.sun_path, tmp_file, sizeof(sa.sun_path));
138 /* wait for socket to become available */
139 errno = ECONNREFUSED;
140 while (errno == ECONNREFUSED) {
141 check = connect(sock_fd, (struct sockaddr *)&sa, sizeof(sa));
142 if (! check)
143 break;
145 fail_unless(errno == ECONNREFUSED,
146 "INTERNAL ERROR: connect() = %d [errno=%d]; expected: 0",
147 check, errno);
148 }
150 close(sock_fd);
152 loop.do_loop = 0;
153 pthread_join(thr, NULL);
155 fail_unless(access(tmp_file, F_OK),
156 "sdb_fe_sock_listen_and_serve() did not clean up "
157 "socket %s", tmp_file);
159 /* should do nothing and not report errors */
160 check = sdb_fe_sock_listen_and_serve(sock, &loop);
161 fail_unless(check == 0,
162 "sdb_fe_sock_listen_and_serve() = %i; "
163 "expected: <0 (do_loop == 0)", check);
164 fail_unless(access(tmp_file, F_OK),
165 "sdb_fe_sock_listen_and_serve() recreated socket "
166 "(do_loop == 0)");
167 }
168 END_TEST
170 Suite *
171 fe_sock_suite(void)
172 {
173 Suite *s = suite_create("frontend::sock");
174 TCase *tc;
176 tc = tcase_create("core");
177 tcase_add_checked_fixture(tc, setup, teardown);
178 tcase_add_test(tc, test_listen_and_serve);
179 suite_add_tcase(s, tc);
181 return s;
182 } /* util_unixsock_suite */
184 /* vim: set tw=78 sw=4 ts=4 noexpandtab : */