• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /* GLib testing framework examples and tests
2  *
3  * Copyright (C) 2010 Red Hat, Inc.
4  *
5  * This library is free software; you can redistribute it and/or
6  * modify it under the terms of the GNU Lesser General Public
7  * License as published by the Free Software Foundation; either
8  * version 2.1 of the License, or (at your option) any later version.
9  *
10  * This library is distributed in the hope that it will be useful,
11  * but WITHOUT ANY WARRANTY; without even the implied warranty of
12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
13  * Lesser General Public License for more details.
14  *
15  * You should have received a copy of the GNU Lesser General
16  * Public License along with this library; if not, see <http://www.gnu.org/licenses/>.
17  */
18 
19 #include "config.h"
20 
21 #include <gio/gio.h>
22 #include <glib/gstdio.h>
23 
24 #ifdef G_OS_UNIX
25 #include <dlfcn.h>
26 #include <fcntl.h>
27 #include <gio/gunixinputstream.h>
28 #include <gio/gunixoutputstream.h>
29 #endif
30 
31 GMainLoop *loop;
32 GPollableInputStream *in;
33 GOutputStream *out;
34 
35 static gboolean
poll_source_callback(GPollableInputStream * in,gpointer user_data)36 poll_source_callback (GPollableInputStream *in,
37 		      gpointer              user_data)
38 {
39   GError *error = NULL;
40   char buf[2];
41   gssize nread;
42   gboolean *success = user_data;
43 
44   g_assert_true (g_pollable_input_stream_is_readable (G_POLLABLE_INPUT_STREAM (in)));
45 
46   nread = g_pollable_input_stream_read_nonblocking (in, buf, 2, NULL, &error);
47   g_assert_no_error (error);
48   g_assert_cmpint (nread, ==, 2);
49   g_assert_cmpstr (buf, ==, "x");
50   g_assert_false (g_pollable_input_stream_is_readable (G_POLLABLE_INPUT_STREAM (in)));
51 
52   *success = TRUE;
53   return G_SOURCE_REMOVE;
54 }
55 
56 static gboolean
check_source_readability_callback(gpointer user_data)57 check_source_readability_callback (gpointer user_data)
58 {
59   gboolean expected = GPOINTER_TO_INT (user_data);
60   gboolean readable;
61 
62   readable = g_pollable_input_stream_is_readable (in);
63   g_assert_cmpint (readable, ==, expected);
64   return G_SOURCE_REMOVE;
65 }
66 
67 static gboolean
write_callback(gpointer user_data)68 write_callback (gpointer user_data)
69 {
70   const char *buf = "x";
71   gssize nwrote;
72   GError *error = NULL;
73 
74   g_assert_true (g_pollable_output_stream_is_writable (G_POLLABLE_OUTPUT_STREAM (out)));
75 
76   nwrote = g_output_stream_write (out, buf, 2, NULL, &error);
77   g_assert_no_error (error);
78   g_assert_cmpint (nwrote, ==, 2);
79   g_assert_true (g_pollable_output_stream_is_writable (G_POLLABLE_OUTPUT_STREAM (out)));
80 
81 /* Give the pipe a few ticks to propagate the write for sockets. On my
82  * iMac i7, 40 works, 30 doesn't. */
83   g_usleep (80L);
84 
85   check_source_readability_callback (GINT_TO_POINTER (TRUE));
86 
87   return G_SOURCE_REMOVE;
88 }
89 
90 static gboolean
check_source_and_quit_callback(gpointer user_data)91 check_source_and_quit_callback (gpointer user_data)
92 {
93   check_source_readability_callback (user_data);
94   g_main_loop_quit (loop);
95   return G_SOURCE_REMOVE;
96 }
97 
98 static void
test_streams(void)99 test_streams (void)
100 {
101   gboolean readable;
102   GError *error = NULL;
103   char buf[1];
104   gssize nread;
105   GSource *poll_source;
106   gboolean success = FALSE;
107 
108   g_assert (g_pollable_input_stream_can_poll (in));
109   g_assert (g_pollable_output_stream_can_poll (G_POLLABLE_OUTPUT_STREAM (out)));
110 
111   readable = g_pollable_input_stream_is_readable (in);
112   g_assert (!readable);
113 
114   nread = g_pollable_input_stream_read_nonblocking (in, buf, 1, NULL, &error);
115   g_assert_cmpint (nread, ==, -1);
116   g_assert_error (error, G_IO_ERROR, G_IO_ERROR_WOULD_BLOCK);
117   g_clear_error (&error);
118 
119   /* Create 4 sources, in decreasing order of priority:
120    *   1. poll source on @in
121    *   2. idle source that checks if @in is readable once
122    *      (it won't be) and then removes itself
123    *   3. idle source that writes a byte to @out, checks that
124    *      @in is now readable, and removes itself
125    *   4. idle source that checks if @in is readable once
126    *      (it won't be, since the poll source will fire before
127    *      this one does) and then quits the loop.
128    *
129    * If the poll source triggers before it should, then it will get a
130    * %G_IO_ERROR_WOULD_BLOCK, and if check() fails in either
131    * direction, we will catch it at some point.
132    */
133 
134   poll_source = g_pollable_input_stream_create_source (in, NULL);
135   g_source_set_priority (poll_source, 1);
136   g_source_set_callback (poll_source, (GSourceFunc) poll_source_callback, &success, NULL);
137   g_source_attach (poll_source, NULL);
138   g_source_unref (poll_source);
139 
140   g_idle_add_full (2, check_source_readability_callback, GINT_TO_POINTER (FALSE), NULL);
141   g_idle_add_full (3, write_callback, NULL, NULL);
142   g_idle_add_full (4, check_source_and_quit_callback, GINT_TO_POINTER (FALSE), NULL);
143 
144   loop = g_main_loop_new (NULL, FALSE);
145   g_main_loop_run (loop);
146   g_main_loop_unref (loop);
147 
148   g_assert_cmpint (success, ==, TRUE);
149 }
150 
151 #ifdef G_OS_UNIX
152 
153 #define g_assert_not_pollable(fd) \
154   G_STMT_START {                                                        \
155     in = G_POLLABLE_INPUT_STREAM (g_unix_input_stream_new (fd, FALSE)); \
156     out = g_unix_output_stream_new (fd, FALSE);                         \
157                                                                         \
158     g_assert (!g_pollable_input_stream_can_poll (in));                  \
159     g_assert (!g_pollable_output_stream_can_poll (                      \
160         G_POLLABLE_OUTPUT_STREAM (out)));                               \
161                                                                         \
162     g_clear_object (&in);                                               \
163     g_clear_object (&out);                                              \
164   } G_STMT_END
165 
166 static void
test_pollable_unix_pipe(void)167 test_pollable_unix_pipe (void)
168 {
169   int pipefds[2], status;
170 
171   g_test_summary ("Test that pipes are considered pollable, just like sockets");
172 
173   status = pipe (pipefds);
174   g_assert_cmpint (status, ==, 0);
175 
176   in = G_POLLABLE_INPUT_STREAM (g_unix_input_stream_new (pipefds[0], TRUE));
177   out = g_unix_output_stream_new (pipefds[1], TRUE);
178 
179   test_streams ();
180 
181   g_object_unref (in);
182   g_object_unref (out);
183 }
184 
185 static void
test_pollable_unix_pty(void)186 test_pollable_unix_pty (void)
187 {
188   int (*openpty_impl) (int *, int *, char *, void *, void *);
189   int a, b, status;
190 #ifdef LIBUTIL_SONAME
191   void *handle;
192 #endif
193 
194   g_test_summary ("Test that PTYs are considered pollable");
195 
196 #ifdef LIBUTIL_SONAME
197   handle = dlopen (LIBUTIL_SONAME, RTLD_GLOBAL | RTLD_LAZY);
198   g_assert_nonnull (handle);
199 #endif
200 
201   openpty_impl = dlsym (RTLD_DEFAULT, "openpty");
202   if (openpty_impl == NULL)
203     {
204       g_test_skip ("System does not support openpty()");
205       goto close_libutil;
206     }
207 
208   status = openpty_impl (&a, &b, NULL, NULL, NULL);
209   if (status == -1)
210     {
211       g_test_skip ("Unable to open PTY");
212       goto close_libutil;
213     }
214 
215   in = G_POLLABLE_INPUT_STREAM (g_unix_input_stream_new (a, TRUE));
216   out = g_unix_output_stream_new (b, TRUE);
217 
218   test_streams ();
219 
220   g_object_unref (in);
221   g_object_unref (out);
222 
223   close (a);
224   close (b);
225 
226 close_libutil:
227 #ifdef LIBUTIL_SONAME
228   dlclose (handle);
229 #else
230   return;
231 #endif
232 }
233 
234 static void
test_pollable_unix_file(void)235 test_pollable_unix_file (void)
236 {
237   int fd;
238 
239   g_test_summary ("Test that regular files are not considered pollable");
240 
241   fd = g_open ("/etc/hosts", O_RDONLY, 0);
242   if (fd == -1)
243     {
244       g_test_skip ("Unable to open /etc/hosts");
245       return;
246     }
247 
248   g_assert_not_pollable (fd);
249 
250   close (fd);
251 }
252 
253 static void
test_pollable_unix_nulldev(void)254 test_pollable_unix_nulldev (void)
255 {
256   int fd;
257 
258   g_test_summary ("Test that /dev/null is not considered pollable, but only if "
259                   "on a system where we are able to tell it apart from devices "
260                   "that actually implement poll");
261 
262 #if defined (HAVE_EPOLL_CREATE) || defined (HAVE_KQUEUE)
263   fd = g_open ("/dev/null", O_RDWR, 0);
264   g_assert_cmpint (fd, !=, -1);
265 
266   g_assert_not_pollable (fd);
267 
268   close (fd);
269 #else
270   g_test_skip ("Cannot detect /dev/null as non-pollable on this system");
271 #endif
272 }
273 
274 static void
test_pollable_converter(void)275 test_pollable_converter (void)
276 {
277   GConverter *converter;
278   GError *error = NULL;
279   GInputStream *ibase;
280   int pipefds[2], status;
281 
282   status = pipe (pipefds);
283   g_assert_cmpint (status, ==, 0);
284 
285   ibase = G_INPUT_STREAM (g_unix_input_stream_new (pipefds[0], TRUE));
286   converter = G_CONVERTER (g_charset_converter_new ("UTF-8", "UTF-8", &error));
287   g_assert_no_error (error);
288 
289   in = G_POLLABLE_INPUT_STREAM (g_converter_input_stream_new (ibase, converter));
290   g_object_unref (converter);
291   g_object_unref (ibase);
292 
293   out = g_unix_output_stream_new (pipefds[1], TRUE);
294 
295   test_streams ();
296 
297   g_object_unref (in);
298   g_object_unref (out);
299 }
300 
301 #endif
302 
303 static void
client_connected(GObject * source,GAsyncResult * result,gpointer user_data)304 client_connected (GObject      *source,
305 		  GAsyncResult *result,
306 		  gpointer      user_data)
307 {
308   GSocketClient *client = G_SOCKET_CLIENT (source);
309   GSocketConnection **conn = user_data;
310   GError *error = NULL;
311 
312   *conn = g_socket_client_connect_finish (client, result, &error);
313   g_assert_no_error (error);
314 }
315 
316 static void
server_connected(GObject * source,GAsyncResult * result,gpointer user_data)317 server_connected (GObject      *source,
318 		  GAsyncResult *result,
319 		  gpointer      user_data)
320 {
321   GSocketListener *listener = G_SOCKET_LISTENER (source);
322   GSocketConnection **conn = user_data;
323   GError *error = NULL;
324 
325   *conn = g_socket_listener_accept_finish (listener, result, NULL, &error);
326   g_assert_no_error (error);
327 }
328 
329 static void
test_pollable_socket(void)330 test_pollable_socket (void)
331 {
332   GInetAddress *iaddr;
333   GSocketAddress *saddr, *effective_address;
334   GSocketListener *listener;
335   GSocketClient *client;
336   GError *error = NULL;
337   GSocketConnection *client_conn = NULL, *server_conn = NULL;
338 
339   iaddr = g_inet_address_new_loopback (G_SOCKET_FAMILY_IPV4);
340   saddr = g_inet_socket_address_new (iaddr, 0);
341   g_object_unref (iaddr);
342 
343   listener = g_socket_listener_new ();
344   g_socket_listener_add_address (listener, saddr,
345 				 G_SOCKET_TYPE_STREAM,
346 				 G_SOCKET_PROTOCOL_TCP,
347 				 NULL,
348 				 &effective_address,
349 				 &error);
350   g_assert_no_error (error);
351   g_object_unref (saddr);
352 
353   client = g_socket_client_new ();
354 
355   g_socket_client_connect_async (client,
356 				 G_SOCKET_CONNECTABLE (effective_address),
357 				 NULL, client_connected, &client_conn);
358   g_socket_listener_accept_async (listener, NULL,
359 				  server_connected, &server_conn);
360 
361   while (!client_conn || !server_conn)
362     g_main_context_iteration (NULL, TRUE);
363 
364   in = G_POLLABLE_INPUT_STREAM (g_io_stream_get_input_stream (G_IO_STREAM (client_conn)));
365   out = g_io_stream_get_output_stream (G_IO_STREAM (server_conn));
366 
367   test_streams ();
368 
369   g_object_unref (client_conn);
370   g_object_unref (server_conn);
371   g_object_unref (client);
372   g_object_unref (listener);
373   g_object_unref (effective_address);
374 }
375 
376 int
main(int argc,char * argv[])377 main (int   argc,
378       char *argv[])
379 {
380   g_test_init (&argc, &argv, NULL);
381 
382 #ifdef G_OS_UNIX
383   g_test_add_func ("/pollable/unix/pipe", test_pollable_unix_pipe);
384   g_test_add_func ("/pollable/unix/pty", test_pollable_unix_pty);
385   g_test_add_func ("/pollable/unix/file", test_pollable_unix_file);
386   g_test_add_func ("/pollable/unix/nulldev", test_pollable_unix_nulldev);
387   g_test_add_func ("/pollable/converter", test_pollable_converter);
388 #endif
389   g_test_add_func ("/pollable/socket", test_pollable_socket);
390 
391   return g_test_run();
392 }
393