Code

6d69ed9ca4a2428c0615a8e4b7e7cafe7c185781
[sysdb.git] / t / unit / frontend / sock_test.c
1 /*
2  * SysDB - t/unit/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 #if HAVE_CONFIG_H
29 #       include "config.h"
30 #endif
32 #include "frontend/sock.h"
33 #include "libsysdb_test.h"
35 #include <check.h>
37 #include <errno.h>
39 #include <stdio.h>
40 #include <stdlib.h>
42 #include <unistd.h>
44 #include <pthread.h>
46 #include <sys/types.h>
47 #include <sys/socket.h>
48 #include <sys/un.h>
50 /*
51  * private variables
52  */
54 static sdb_fe_socket_t *sock;
56 static void
57 setup(void)
58 {
59         sock = sdb_fe_sock_create();
60         fail_unless(sock != NULL,
61                         "sdb_fe_sock_create() = NULL; expected frontend sock object");
62 } /* setup */
64 static void
65 teardown(void)
66 {
67         sdb_fe_sock_destroy(sock);
68         sock = NULL;
69 } /* teardown */
71 static void
72 sock_listen(char *tmp_file)
73 {
74         char sock_addr[strlen("unix:") + strlen(tmp_file) + 1];
75         int check;
77         sprintf(sock_addr, "unix:%s", tmp_file);
78         check = sdb_fe_sock_add_listener(sock, sock_addr, NULL);
79         fail_unless(check == 0,
80                         "sdb_fe_sock_add_listener(%s) = %i; expected: 0",
81                         sock_addr, check);
82 } /* sock_listen */
84 /*
85  * parallel testing
86  */
88 static void *
89 sock_handler(void *data)
90 {
91         sdb_fe_loop_t *loop = data;
92         int check;
94         check = sdb_fe_sock_listen_and_serve(sock, loop);
95         fail_unless(check == 0,
96                         "sdb_fe_sock_listen_and_serve() = %i; "
97                         "expected: 0 (after adding listener)", check);
98         return NULL;
99 } /* sock_handler */
101 /*
102  * tests
103  */
105 START_TEST(test_listen_and_serve)
107         sdb_fe_loop_t loop = SDB_FE_LOOP_INIT;
109         char tmp_file[] = "sock_test_socket.XXXXXX";
110         int check;
112         pthread_t thr;
114         int fd, sock_fd;
115         struct sockaddr_un sa;
117         check = sdb_fe_sock_listen_and_serve(sock, &loop);
118         fail_unless(check < 0,
119                         "sdb_fe_sock_listen_and_serve() = %i; "
120                         "expected: <0 (before adding listeners)", check);
122         fd = mkstemp(tmp_file);
123         unlink(tmp_file);
124         close(fd);
125         sock_listen(tmp_file);
127         loop.do_loop = 1;
128         check = pthread_create(&thr, /* attr = */ NULL, sock_handler, &loop);
129         fail_unless(check == 0,
130                         "INTERNAL ERROR: pthread_create() = %i; expected: 0", check);
132         sock_fd = socket(AF_UNIX, SOCK_STREAM, 0);
133         fail_unless(sock_fd >= 0,
134                         "INTERNAL ERROR: socket() = %d; expected: >= 0", sock_fd);
136         sa.sun_family = AF_UNIX;
137         strncpy(sa.sun_path, tmp_file, sizeof(sa.sun_path));
139         /* wait for socket to become available */
140         errno = ECONNREFUSED;
141         while (errno == ECONNREFUSED) {
142                 check = connect(sock_fd, (struct sockaddr *)&sa, sizeof(sa));
143                 if (! check)
144                         break;
146                 fail_unless(errno == ECONNREFUSED,
147                                 "INTERNAL ERROR: connect() = %d [errno=%d]; expected: 0",
148                                 check, errno);
149         }
151         close(sock_fd);
153         loop.do_loop = 0;
154         pthread_join(thr, NULL);
156         fail_unless(access(tmp_file, F_OK),
157                         "sdb_fe_sock_listen_and_serve() did not clean up "
158                         "socket %s", tmp_file);
160         /* should do nothing and not report errors */
161         check = sdb_fe_sock_listen_and_serve(sock, &loop);
162         fail_unless(check == 0,
163                         "sdb_fe_sock_listen_and_serve() = %i; "
164                         "expected: <0 (do_loop == 0)", check);
165         fail_unless(access(tmp_file, F_OK),
166                         "sdb_fe_sock_listen_and_serve() recreated socket "
167                         "(do_loop == 0)");
169 END_TEST
171 Suite *
172 fe_sock_suite(void)
174         Suite *s = suite_create("frontend::sock");
175         TCase *tc;
177         tc = tcase_create("core");
178         tcase_add_checked_fixture(tc, setup, teardown);
179         tcase_add_test(tc, test_listen_and_serve);
180         suite_add_tcase(s, tc);
182         return s;
183 } /* util_unixsock_suite */
185 /* vim: set tw=78 sw=4 ts=4 noexpandtab : */