blob: d91507fbf53c60bc4efcd3c9524e650ebab705a8 [file] [log] [blame]
Roger Meierc1010922010-11-26 10:17:48 +00001/*
2 * Licensed to the Apache Software Foundation (ASF) under one
3 * or more contributor license agreements. See the NOTICE file
4 * distributed with this work for additional information
5 * regarding copyright ownership. The ASF licenses this file
6 * to you under the Apache License, Version 2.0 (the
7 * "License"); you may not use this file except in compliance
8 * with the License. You may obtain a copy of the License at
9 *
10 * http://www.apache.org/licenses/LICENSE-2.0
11 *
12 * Unless required by applicable law or agreed to in writing,
13 * software distributed under the License is distributed on an
14 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
15 * KIND, either express or implied. See the License for the
16 * specific language governing permissions and limitations
17 * under the License.
18 */
19
Roger Meier213a6642010-10-27 12:30:11 +000020#include <assert.h>
21#include <netdb.h>
Roger Meier63243c62014-09-29 20:29:58 +020022#include <sys/wait.h>
Roger Meier213a6642010-10-27 12:30:11 +000023
Roger Meiere3da7682013-01-11 11:41:53 +010024#include <thrift/c_glib/transport/thrift_transport.h>
Roger Meier63243c62014-09-29 20:29:58 +020025#include <thrift/c_glib/transport/thrift_buffered_transport.h>
Roger Meiere3da7682013-01-11 11:41:53 +010026#include <thrift/c_glib/transport/thrift_server_transport.h>
27#include <thrift/c_glib/transport/thrift_server_socket.h>
Roger Meier213a6642010-10-27 12:30:11 +000028
29#define TEST_DATA { 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j' }
30
31/* substituted functions to test failures of system and library calls */
32static int socket_error = 0;
33int
34my_socket(int domain, int type, int protocol)
35{
36 if (socket_error == 0)
37 {
38 return socket (domain, type, protocol);
39 }
40 return -1;
41}
42
43static int recv_error = 0;
44ssize_t
45my_recv(int socket, void *buffer, size_t length, int flags)
46{
47 if (recv_error == 0)
48 {
49 return recv (socket, buffer, length, flags);
50 }
51 return -1;
52}
53
54static int send_error = 0;
55ssize_t
56my_send(int socket, const void *buffer, size_t length, int flags)
57{
58 if (send_error == 0)
59 {
60 return send (socket, buffer, length, flags);
61 }
62 return -1;
63}
64
65#define socket my_socket
66#define recv my_recv
67#define send my_send
Roger Meiere3da7682013-01-11 11:41:53 +010068#include "../src/thrift/c_glib/transport/thrift_socket.c"
Roger Meier213a6642010-10-27 12:30:11 +000069#undef socket
70#undef recv
71#undef send
72
Roger Meier213a6642010-10-27 12:30:11 +000073static void thrift_socket_server (const int port);
74
75/* test object creation and destruction */
76static void
77test_create_and_destroy(void)
78{
79 gchar *hostname = NULL;
80 guint port = 0;
81
82 GObject *object = NULL;
83 object = g_object_new (THRIFT_TYPE_SOCKET, NULL);
84 assert (object != NULL);
85 g_object_get (G_OBJECT(object), "hostname", &hostname, "port", &port, NULL);
86 g_free (hostname);
87
88 g_object_unref (object);
89}
90
91static void
92test_open_and_close(void)
93{
94 ThriftSocket *tsocket = NULL;
95 ThriftTransport *transport = NULL;
96 GError *err = NULL;
97
98 /* open a connection and close it */
99 tsocket = g_object_new (THRIFT_TYPE_SOCKET, "hostname", "localhost",
100 "port", 51188, NULL);
101 transport = THRIFT_TRANSPORT (tsocket);
102 thrift_socket_open (transport, NULL);
103 assert (thrift_socket_is_open (transport) == TRUE);
104 thrift_socket_close (transport, NULL);
105 assert (thrift_socket_is_open (transport) == FALSE);
106
107 /* test close failure */
108 tsocket->sd = -1;
109 thrift_socket_close (transport, NULL);
110 g_object_unref (tsocket);
111
112 /* try a hostname lookup failure */
113 tsocket = g_object_new (THRIFT_TYPE_SOCKET, "hostname", "localhost.broken",
114 NULL);
115 transport = THRIFT_TRANSPORT (tsocket);
116 assert (thrift_socket_open (transport, &err) == FALSE);
117 g_object_unref (tsocket);
118 g_error_free (err);
119 err = NULL;
120
121 /* try an error call to socket() */
122 tsocket = g_object_new (THRIFT_TYPE_SOCKET, "hostname", "localhost", NULL);
123 transport = THRIFT_TRANSPORT (tsocket);
124 socket_error = 1;
125 assert (thrift_socket_open (transport, &err) == FALSE);
126 socket_error = 0;
127 g_object_unref (tsocket);
128 g_error_free (err);
129}
130
131static void
132test_read_and_write(void)
133{
134 int status;
135 pid_t pid;
136 ThriftSocket *tsocket = NULL;
137 ThriftTransport *transport = NULL;
138 int port = 51199;
139 guchar buf[10] = TEST_DATA; /* a buffer */
140
141 pid = fork ();
142 assert ( pid >= 0 );
143
144 if ( pid == 0 )
145 {
146 /* child listens */
147 thrift_socket_server (port);
148 exit (0);
149 } else {
150 /* parent connects, wait a bit for the socket to be created */
151 sleep (1);
152
153 tsocket = g_object_new (THRIFT_TYPE_SOCKET, "hostname", "localhost",
154 "port", port, NULL);
155 transport = THRIFT_TRANSPORT (tsocket);
156 assert (thrift_socket_open (transport, NULL) == TRUE);
157 assert (thrift_socket_is_open (transport));
158 thrift_socket_write (transport, buf, 10, NULL);
159
160 /* write fail */
161 send_error = 1;
162 thrift_socket_write (transport, buf, 1, NULL);
163 send_error = 0;
164
165 thrift_socket_write_end (transport, NULL);
166 thrift_socket_flush (transport, NULL);
167 thrift_socket_close (transport, NULL);
168 g_object_unref (tsocket);
169
170 assert ( wait (&status) == pid );
171 assert ( status == 0 );
172 }
173}
174
Roger Meier63243c62014-09-29 20:29:58 +0200175/* test ThriftSocket's peek() implementation */
176static void
177test_peek(void)
178{
179 gint status;
180 pid_t pid;
181 guint port = 51199;
182 gchar data = 'A';
183 ThriftTransport *client_transport;
184 GError *error = NULL;
185
186 client_transport = g_object_new (THRIFT_TYPE_SOCKET,
187 "hostname", "localhost",
188 "port", port,
189 NULL);
190
191 /* thrift_transport_peek returns FALSE when the socket is closed */
192 g_assert (thrift_transport_is_open (client_transport) == FALSE);
193 g_assert (thrift_transport_peek (client_transport, &error) == FALSE);
194 g_assert (error == NULL);
195
196 pid = fork ();
197 g_assert (pid >= 0);
198
199 if (pid == 0)
200 {
201 ThriftServerTransport *server_transport = NULL;
202
203 g_object_unref (client_transport);
204
205 /* child listens */
206 server_transport = g_object_new (THRIFT_TYPE_SERVER_SOCKET,
207 "port", port,
208 NULL);
209 g_assert (server_transport != NULL);
210
211 thrift_server_transport_listen (server_transport, &error);
212 g_assert (error == NULL);
213
214 client_transport = g_object_new
215 (THRIFT_TYPE_BUFFERED_TRANSPORT,
216 "transport", thrift_server_transport_accept (server_transport, &error),
217 "r_buf_size", 0,
218 "w_buf_size", sizeof data,
219 NULL);
220 g_assert (error == NULL);
221 g_assert (client_transport != NULL);
222
223 /* write exactly one character to the client */
224 g_assert (thrift_transport_write (client_transport,
225 &data,
226 sizeof data,
227 &error) == TRUE);
228
229 thrift_transport_flush (client_transport, &error);
230 thrift_transport_write_end (client_transport, &error);
231 thrift_transport_close (client_transport, &error);
232
233 g_object_unref (client_transport);
234 g_object_unref (server_transport);
235
236 exit (0);
237 }
238 else {
239 /* parent connects, wait a bit for the socket to be created */
240 sleep (1);
241
242 /* connect to the child */
243 thrift_transport_open (client_transport, &error);
244 g_assert (error == NULL);
245 g_assert (thrift_transport_is_open (client_transport) == TRUE);
246
247 /* thrift_transport_peek returns TRUE when the socket is open and there is
248 data available to be read */
249 g_assert (thrift_transport_peek (client_transport, &error) == TRUE);
250 g_assert (error == NULL);
251
252 /* read exactly one character from the server */
253 g_assert_cmpint (thrift_transport_read (client_transport,
254 &data,
255 sizeof data,
256 &error), ==, sizeof data);
257
258 /* thrift_transport_peek returns FALSE when the socket is open but there is
259 no (more) data available to be read */
260 g_assert (thrift_transport_is_open (client_transport) == TRUE);
261 g_assert (thrift_transport_peek (client_transport, &error) == FALSE);
262 g_assert (error == NULL);
263
264 thrift_transport_read_end (client_transport, &error);
265 thrift_transport_close (client_transport, &error);
266
267 g_object_unref (client_transport);
268
269 g_assert (wait (&status) == pid);
270 g_assert (status == 0);
271 }
272}
273
Roger Meier213a6642010-10-27 12:30:11 +0000274static void
275thrift_socket_server (const int port)
276{
277 int bytes = 0;
278 ThriftServerTransport *transport = NULL;
279 ThriftTransport *client = NULL;
280 guchar buf[10]; /* a buffer */
281 guchar match[10] = TEST_DATA;
282
283 ThriftServerSocket *tsocket = g_object_new (THRIFT_TYPE_SERVER_SOCKET,
284 "port", port, NULL);
285
286 transport = THRIFT_SERVER_TRANSPORT (tsocket);
287 thrift_server_transport_listen (transport, NULL);
288 client = thrift_server_transport_accept (transport, NULL);
289 assert (client != NULL);
290
291 /* read 10 bytes */
292 bytes = thrift_socket_read (client, buf, 10, NULL);
293 assert (bytes == 10); /* make sure we've read 10 bytes */
294 assert ( memcmp(buf, match, 10) == 0 ); /* make sure what we got matches */
295
296 /* failed read */
297 recv_error = 1;
298 thrift_socket_read (client, buf, 1, NULL);
299 recv_error = 0;
300
301 thrift_socket_read_end (client, NULL);
302 thrift_socket_close (client, NULL);
303 g_object_unref (tsocket);
304 g_object_unref (client);
305}
306
307int
Roger Meierc1010922010-11-26 10:17:48 +0000308main(int argc, char *argv[])
Roger Meier213a6642010-10-27 12:30:11 +0000309{
Jens Geyer1c190272015-07-28 23:15:18 +0200310#if (!GLIB_CHECK_VERSION (2, 36, 0))
Roger Meier213a6642010-10-27 12:30:11 +0000311 g_type_init();
Jens Geyer1c190272015-07-28 23:15:18 +0200312#endif
313
Roger Meierc1010922010-11-26 10:17:48 +0000314 g_test_init (&argc, &argv, NULL);
Roger Meier213a6642010-10-27 12:30:11 +0000315
Roger Meierc1010922010-11-26 10:17:48 +0000316 g_test_add_func ("/testtransportsocket/CreateAndDestroy", test_create_and_destroy);
317 g_test_add_func ("/testtransportsocket/OpenAndClose", test_open_and_close);
318 g_test_add_func ("/testtransportsocket/ReadAndWrite", test_read_and_write);
Roger Meier63243c62014-09-29 20:29:58 +0200319 g_test_add_func ("/testtransportsocket/Peek", test_peek);
Roger Meierc1010922010-11-26 10:17:48 +0000320
321 return g_test_run ();
Roger Meier213a6642010-10-27 12:30:11 +0000322}
323