1 /* GLib testing framework examples and tests
2 * Copyright (C) 2008 Red Hat, Inc
4 * SPDX-License-Identifier: LicenseRef-old-glib-tests
6 * This work is provided "as is"; redistribution and modification
7 * in whole or in part, in any medium, physical or electronic is
8 * permitted without restriction.
10 * This work 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.
14 * In no event shall the authors or contributors be liable for any
15 * direct, indirect, incidental, special, exemplary, or consequential
16 * damages (including, but not limited to, procurement of substitute
17 * goods or services; loss of use, data, or profits; or business
18 * interruption) however caused and on any theory of liability, whether
19 * in contract, strict liability, or tort (including negligence or
20 * otherwise) arising in any way out of the use of this software, even
21 * if advised of the possibility of such damage.
25 #include <gio/gunixinputstream.h>
26 #include <gio/gunixoutputstream.h>
28 #include <glib/glib-unix.h>
35 /* sizeof(DATA) will give the number of bytes in the array, plus the terminating nul */
36 static const gchar DATA[] = "abcdefghijklmnopqrstuvwxyz";
38 int writer_pipe[2], reader_pipe[2];
39 GCancellable *writer_cancel, *reader_cancel, *main_cancel;
44 writer_thread (gpointer user_data)
47 gssize nwrote, offset;
50 out = g_unix_output_stream_new (writer_pipe[1], TRUE);
57 while (offset < (gssize) sizeof (DATA))
59 nwrote = g_output_stream_write (out, DATA + offset,
60 sizeof (DATA) - offset,
62 if (nwrote <= 0 || err != NULL)
67 g_assert_true (nwrote > 0 || err != NULL);
71 if (g_cancellable_is_cancelled (writer_cancel))
74 g_cancellable_cancel (main_cancel);
79 g_warning ("writer: %s", err->message);
80 g_assert_not_reached ();
84 reader_thread (gpointer user_data)
87 gssize nread = 0, total;
89 char buf[sizeof (DATA)];
91 in = g_unix_input_stream_new (reader_pipe[0], TRUE);
96 while (total < (gssize) sizeof (DATA))
98 nread = g_input_stream_read (in, buf + total, sizeof (buf) - total,
100 if (nread <= 0 || err != NULL)
110 g_assert_no_error (err);
116 g_assert_cmpstr (buf, ==, DATA);
117 g_assert_false (g_cancellable_is_cancelled (reader_cancel));
121 g_warning ("reader: %s", err->message);
122 g_assert_not_reached ();
125 static char main_buf[sizeof (DATA)];
126 static gssize main_len, main_offset;
128 static void main_thread_read (GObject *source, GAsyncResult *res, gpointer user_data);
129 static void main_thread_skipped (GObject *source, GAsyncResult *res, gpointer user_data);
130 static void main_thread_wrote (GObject *source, GAsyncResult *res, gpointer user_data);
133 do_main_cancel (GOutputStream *out)
135 g_output_stream_close (out, NULL, NULL);
136 g_main_loop_quit (loop);
140 main_thread_skipped (GObject *source, GAsyncResult *res, gpointer user_data)
142 GInputStream *in = G_INPUT_STREAM (source);
143 GOutputStream *out = user_data;
147 nskipped = g_input_stream_skip_finish (in, res, &err);
149 if (g_error_matches (err, G_IO_ERROR, G_IO_ERROR_CANCELLED))
151 g_assert_true (g_cancellable_is_cancelled (main_cancel));
152 do_main_cancel (out);
153 g_clear_error (&err);
157 g_assert_no_error (err);
159 main_offset += nskipped;
160 if (main_offset == main_len)
163 g_output_stream_write_async (out, main_buf, main_len,
164 G_PRIORITY_DEFAULT, main_cancel,
165 main_thread_wrote, in);
169 g_input_stream_skip_async (in, main_len - main_offset,
170 G_PRIORITY_DEFAULT, main_cancel,
171 main_thread_skipped, out);
176 main_thread_read (GObject *source, GAsyncResult *res, gpointer user_data)
178 GInputStream *in = G_INPUT_STREAM (source);
179 GOutputStream *out = user_data;
183 nread = g_input_stream_read_finish (in, res, &err);
185 if (g_error_matches (err, G_IO_ERROR, G_IO_ERROR_CANCELLED))
187 g_assert_true (g_cancellable_is_cancelled (main_cancel));
188 do_main_cancel (out);
189 g_clear_error (&err);
193 g_assert_no_error (err);
195 main_offset += nread;
196 if (main_offset == sizeof (DATA))
198 main_len = main_offset;
200 /* Now skip the same amount */
201 g_input_stream_skip_async (in, main_len,
202 G_PRIORITY_DEFAULT, main_cancel,
203 main_thread_skipped, out);
207 g_input_stream_read_async (in, main_buf, sizeof (main_buf),
208 G_PRIORITY_DEFAULT, main_cancel,
209 main_thread_read, out);
214 main_thread_wrote (GObject *source, GAsyncResult *res, gpointer user_data)
216 GOutputStream *out = G_OUTPUT_STREAM (source);
217 GInputStream *in = user_data;
221 nwrote = g_output_stream_write_finish (out, res, &err);
223 if (g_error_matches (err, G_IO_ERROR, G_IO_ERROR_CANCELLED))
225 g_assert_true (g_cancellable_is_cancelled (main_cancel));
226 do_main_cancel (out);
227 g_clear_error (&err);
231 g_assert_no_error (err);
232 g_assert_cmpint (nwrote, <=, main_len - main_offset);
234 main_offset += nwrote;
235 if (main_offset == main_len)
238 g_input_stream_read_async (in, main_buf, sizeof (main_buf),
239 G_PRIORITY_DEFAULT, main_cancel,
240 main_thread_read, out);
244 g_output_stream_write_async (out, main_buf + main_offset,
245 main_len - main_offset,
246 G_PRIORITY_DEFAULT, main_cancel,
247 main_thread_wrote, in);
252 timeout (gpointer cancellable)
254 g_cancellable_cancel (cancellable);
259 test_pipe_io (gconstpointer nonblocking)
261 GThread *writer, *reader;
265 /* Split off two (additional) threads, a reader and a writer. From
266 * the writer thread, write data synchronously in small chunks,
267 * which gets alternately read and skipped asynchronously by the
268 * main thread and then (if not skipped) written asynchronously to
269 * the reader thread, which reads it synchronously. Eventually a
270 * timeout in the main thread will cause it to cancel the writer
271 * thread, which will in turn cancel the read op in the main thread,
272 * which will then close the pipe to the reader thread, causing the
276 g_assert_true (pipe (writer_pipe) == 0 && pipe (reader_pipe) == 0);
280 GError *error = NULL;
282 g_unix_set_fd_nonblocking (writer_pipe[0], TRUE, &error);
283 g_assert_no_error (error);
284 g_unix_set_fd_nonblocking (writer_pipe[1], TRUE, &error);
285 g_assert_no_error (error);
286 g_unix_set_fd_nonblocking (reader_pipe[0], TRUE, &error);
287 g_assert_no_error (error);
288 g_unix_set_fd_nonblocking (reader_pipe[1], TRUE, &error);
289 g_assert_no_error (error);
292 writer_cancel = g_cancellable_new ();
293 reader_cancel = g_cancellable_new ();
294 main_cancel = g_cancellable_new ();
296 writer = g_thread_new ("writer", writer_thread, NULL);
297 reader = g_thread_new ("reader", reader_thread, NULL);
299 in = g_unix_input_stream_new (writer_pipe[0], TRUE);
300 out = g_unix_output_stream_new (reader_pipe[1], TRUE);
302 g_input_stream_read_async (in, main_buf, sizeof (main_buf),
303 G_PRIORITY_DEFAULT, main_cancel,
304 main_thread_read, out);
306 g_timeout_add (500, timeout, writer_cancel);
308 loop = g_main_loop_new (NULL, TRUE);
309 g_main_loop_run (loop);
310 g_main_loop_unref (loop);
312 g_thread_join (reader);
313 g_thread_join (writer);
315 g_object_unref (main_cancel);
316 g_object_unref (reader_cancel);
317 g_object_unref (writer_cancel);
319 g_object_unref (out);
325 GUnixInputStream *is;
326 GUnixOutputStream *os;
330 is = G_UNIX_INPUT_STREAM (g_unix_input_stream_new (0, TRUE));
333 "close-fd", &close_fd,
335 g_assert_cmpint (fd, ==, 0);
336 g_assert_true (close_fd);
338 g_unix_input_stream_set_close_fd (is, FALSE);
339 g_assert_false (g_unix_input_stream_get_close_fd (is));
340 g_assert_cmpint (g_unix_input_stream_get_fd (is), ==, 0);
342 g_assert_false (g_input_stream_has_pending (G_INPUT_STREAM (is)));
346 os = G_UNIX_OUTPUT_STREAM (g_unix_output_stream_new (1, TRUE));
349 "close-fd", &close_fd,
351 g_assert_cmpint (fd, ==, 1);
352 g_assert_true (close_fd);
354 g_unix_output_stream_set_close_fd (os, FALSE);
355 g_assert_false (g_unix_output_stream_get_close_fd (os));
356 g_assert_cmpint (g_unix_output_stream_get_fd (os), ==, 1);
358 g_assert_false (g_output_stream_has_pending (G_OUTPUT_STREAM (os)));
366 const guint8 *write_data;
371 test_read_write_write_thread (gpointer user_data)
373 TestReadWriteData *data = user_data;
375 GError *error = NULL;
378 res = g_output_stream_write_all (data->os, data->write_data, 1024, &bytes_written, NULL, &error);
380 g_assert_no_error (error);
381 g_assert_cmpuint (bytes_written, ==, 1024);
387 test_read_write_read_thread (gpointer user_data)
389 TestReadWriteData *data = user_data;
391 GError *error = NULL;
394 res = g_input_stream_read_all (data->is, data->read_data, 1024, &bytes_read, NULL, &error);
396 g_assert_no_error (error);
397 g_assert_cmpuint (bytes_read, ==, 1024);
403 test_read_write_writev_thread (gpointer user_data)
405 TestReadWriteData *data = user_data;
407 GError *error = NULL;
409 GOutputVector vectors[3];
411 vectors[0].buffer = data->write_data;
412 vectors[0].size = 256;
413 vectors[1].buffer = data->write_data + 256;
414 vectors[1].size = 256;
415 vectors[2].buffer = data->write_data + 512;
416 vectors[2].size = 512;
418 res = g_output_stream_writev_all (data->os, vectors, G_N_ELEMENTS (vectors), &bytes_written, NULL, &error);
420 g_assert_no_error (error);
421 g_assert_cmpuint (bytes_written, ==, 1024);
426 /* test if normal writing/reading from a pipe works */
428 test_read_write (gconstpointer user_data)
430 gboolean writev = GPOINTER_TO_INT (user_data);
431 GUnixInputStream *is;
432 GUnixOutputStream *os;
434 guint8 data_write[1024], data_read[1024];
436 GThread *write_thread, *read_thread;
437 TestReadWriteData data;
439 for (i = 0; i < sizeof (data_write); i++)
442 g_assert_cmpint (pipe (fd), ==, 0);
444 is = G_UNIX_INPUT_STREAM (g_unix_input_stream_new (fd[0], TRUE));
445 os = G_UNIX_OUTPUT_STREAM (g_unix_output_stream_new (fd[1], TRUE));
447 data.is = G_INPUT_STREAM (is);
448 data.os = G_OUTPUT_STREAM (os);
449 data.read_data = data_read;
450 data.write_data = data_write;
453 write_thread = g_thread_new ("writer", test_read_write_writev_thread, &data);
455 write_thread = g_thread_new ("writer", test_read_write_write_thread, &data);
456 read_thread = g_thread_new ("reader", test_read_write_read_thread, &data);
458 g_thread_join (write_thread);
459 g_thread_join (read_thread);
461 g_assert_cmpmem (data_write, sizeof data_write, data_read, sizeof data_read);
467 /* test if g_pollable_output_stream_write_nonblocking() and
468 * g_pollable_output_stream_read_nonblocking() correctly return WOULD_BLOCK
469 * and correctly reset their status afterwards again, and all data that is
470 * written can also be read again.
473 test_write_wouldblock (void)
476 g_test_skip ("F_GETPIPE_SZ not defined");
477 #else /* if F_GETPIPE_SZ */
478 GUnixInputStream *is;
479 GUnixOutputStream *os;
482 guint8 data_write[1024], data_read[1024];
487 for (i = 0; i < sizeof (data_write); i++)
490 g_assert_cmpint (pipe (fd), ==, 0);
492 g_assert_cmpint (fcntl (fd[0], F_SETPIPE_SZ, 4096, NULL), !=, 0);
493 retval = fcntl (fd[0], F_GETPIPE_SZ);
494 g_assert_cmpint (retval, >=, 0);
495 pipe_capacity = (gsize) retval;
496 g_assert_cmpint (pipe_capacity, >=, 4096);
497 g_assert_cmpint (pipe_capacity % 1024, >=, 0);
499 is = G_UNIX_INPUT_STREAM (g_unix_input_stream_new (fd[0], TRUE));
500 os = G_UNIX_OUTPUT_STREAM (g_unix_output_stream_new (fd[1], TRUE));
502 /* Run the whole thing three times to make sure that the streams
503 * reset the writability/readability state again */
504 for (i = 0; i < 3; i++) {
505 gssize written = 0, written_complete = 0;
506 gssize read = 0, read_complete = 0;
510 written_complete += written;
511 written = g_pollable_output_stream_write_nonblocking (G_POLLABLE_OUTPUT_STREAM (os),
519 g_assert_cmpuint (written_complete, >, 0);
520 g_assert_nonnull (err);
521 g_assert_error (err, G_IO_ERROR, G_IO_ERROR_WOULD_BLOCK);
522 g_clear_error (&err);
526 read_complete += read;
527 read = g_pollable_input_stream_read_nonblocking (G_POLLABLE_INPUT_STREAM (is),
533 g_assert_cmpmem (data_read, read, data_write, sizeof (data_write));
537 g_assert_cmpuint (read_complete, ==, written_complete);
538 g_assert_nonnull (err);
539 g_assert_error (err, G_IO_ERROR, G_IO_ERROR_WOULD_BLOCK);
540 g_clear_error (&err);
545 #endif /* if F_GETPIPE_SZ */
548 /* test if g_pollable_output_stream_writev_nonblocking() and
549 * g_pollable_output_stream_read_nonblocking() correctly return WOULD_BLOCK
550 * and correctly reset their status afterwards again, and all data that is
551 * written can also be read again.
554 test_writev_wouldblock (void)
557 g_test_skip ("F_GETPIPE_SZ not defined");
558 #else /* if F_GETPIPE_SZ */
559 GUnixInputStream *is;
560 GUnixOutputStream *os;
563 guint8 data_write[1024], data_read[1024];
567 GOutputVector vectors[4];
570 for (i = 0; i < sizeof (data_write); i++)
573 g_assert_cmpint (pipe (fd), ==, 0);
575 g_assert_cmpint (fcntl (fd[0], F_SETPIPE_SZ, 4096, NULL), !=, 0);
576 retval = fcntl (fd[0], F_GETPIPE_SZ);
577 g_assert_cmpint (retval, >=, 0);
578 pipe_capacity = (gsize) retval;
579 g_assert_cmpint (pipe_capacity, >=, 4096);
580 g_assert_cmpint (pipe_capacity % 1024, >=, 0);
582 is = G_UNIX_INPUT_STREAM (g_unix_input_stream_new (fd[0], TRUE));
583 os = G_UNIX_OUTPUT_STREAM (g_unix_output_stream_new (fd[1], TRUE));
585 /* Run the whole thing three times to make sure that the streams
586 * reset the writability/readability state again */
587 for (i = 0; i < 3; i++) {
588 gsize written = 0, written_complete = 0;
589 gssize read = 0, read_complete = 0;
593 written_complete += written;
595 vectors[0].buffer = data_write;
596 vectors[0].size = 256;
597 vectors[1].buffer = data_write + 256;
598 vectors[1].size = 256;
599 vectors[2].buffer = data_write + 512;
600 vectors[2].size = 256;
601 vectors[3].buffer = data_write + 768;
602 vectors[3].size = 256;
604 res = g_pollable_output_stream_writev_nonblocking (G_POLLABLE_OUTPUT_STREAM (os),
606 G_N_ELEMENTS (vectors),
611 while (res == G_POLLABLE_RETURN_OK);
613 g_assert_cmpuint (written_complete, >, 0);
615 g_assert_cmpint (res, ==, G_POLLABLE_RETURN_WOULD_BLOCK);
616 /* writev() on UNIX streams either succeeds fully or not at all */
617 g_assert_cmpuint (written, ==, 0);
621 read_complete += read;
622 read = g_pollable_input_stream_read_nonblocking (G_POLLABLE_INPUT_STREAM (is),
628 g_assert_cmpmem (data_read, read, data_write, sizeof (data_write));
632 g_assert_cmpuint (read_complete, ==, written_complete);
633 g_assert_nonnull (err);
634 g_assert_error (err, G_IO_ERROR, G_IO_ERROR_WOULD_BLOCK);
635 g_clear_error (&err);
640 #endif /* if F_GETPIPE_SZ */
645 write_async_wouldblock_cb (GUnixOutputStream *os,
646 GAsyncResult *result,
649 gsize *bytes_written = user_data;
652 g_output_stream_write_all_finish (G_OUTPUT_STREAM (os), result, bytes_written, &err);
653 g_assert_no_error (err);
657 read_async_wouldblock_cb (GUnixInputStream *is,
658 GAsyncResult *result,
661 gsize *bytes_read = user_data;
664 g_input_stream_read_all_finish (G_INPUT_STREAM (is), result, bytes_read, &err);
665 g_assert_no_error (err);
667 #endif /* if F_GETPIPE_SZ */
669 /* test if the async implementation of write_all() and read_all() in G*Stream
670 * around the GPollable*Stream API is working correctly.
673 test_write_async_wouldblock (void)
676 g_test_skip ("F_GETPIPE_SZ not defined");
677 #else /* if F_GETPIPE_SZ */
678 GUnixInputStream *is;
679 GUnixOutputStream *os;
681 guint8 *data, *data_read;
685 gsize bytes_written = 0, bytes_read = 0;
687 g_assert_cmpint (pipe (fd), ==, 0);
689 /* FIXME: These should not be needed but otherwise
690 * g_unix_output_stream_write() will block because
691 * a) the fd is writable
692 * b) writing 4x capacity will block because writes are atomic
693 * c) the fd is blocking
695 * See https://gitlab.gnome.org/GNOME/glib/issues/1654
697 g_unix_set_fd_nonblocking (fd[0], TRUE, NULL);
698 g_unix_set_fd_nonblocking (fd[1], TRUE, NULL);
700 g_assert_cmpint (fcntl (fd[0], F_SETPIPE_SZ, 4096, NULL), !=, 0);
701 retval = fcntl (fd[0], F_GETPIPE_SZ);
702 g_assert_cmpint (retval, >=, 0);
703 pipe_capacity = (gsize) retval;
704 g_assert_cmpint (pipe_capacity, >=, 4096);
706 data = g_new (guint8, 4 * pipe_capacity);
707 for (i = 0; i < 4 * pipe_capacity; i++)
709 data_read = g_new (guint8, 4 * pipe_capacity);
711 is = G_UNIX_INPUT_STREAM (g_unix_input_stream_new (fd[0], TRUE));
712 os = G_UNIX_OUTPUT_STREAM (g_unix_output_stream_new (fd[1], TRUE));
714 g_output_stream_write_all_async (G_OUTPUT_STREAM (os),
719 (GAsyncReadyCallback) write_async_wouldblock_cb,
722 g_input_stream_read_all_async (G_INPUT_STREAM (is),
727 (GAsyncReadyCallback) read_async_wouldblock_cb,
730 while (bytes_written == 0 && bytes_read == 0)
731 g_main_context_iteration (NULL, TRUE);
733 g_assert_cmpuint (bytes_written, ==, 4 * pipe_capacity);
734 g_assert_cmpuint (bytes_read, ==, 4 * pipe_capacity);
735 g_assert_cmpmem (data_read, bytes_read, data, bytes_written);
742 #endif /* if F_GETPIPE_SZ */
747 writev_async_wouldblock_cb (GUnixOutputStream *os,
748 GAsyncResult *result,
751 gsize *bytes_written = user_data;
754 g_output_stream_writev_all_finish (G_OUTPUT_STREAM (os), result, bytes_written, &err);
755 g_assert_no_error (err);
757 #endif /* if F_GETPIPE_SZ */
759 /* test if the async implementation of writev_all() and read_all() in G*Stream
760 * around the GPollable*Stream API is working correctly.
763 test_writev_async_wouldblock (void)
766 g_test_skip ("F_GETPIPE_SZ not defined");
767 #else /* if F_GETPIPE_SZ */
768 GUnixInputStream *is;
769 GUnixOutputStream *os;
771 guint8 *data, *data_read;
775 gsize bytes_written = 0, bytes_read = 0;
776 GOutputVector vectors[4];
778 g_assert_cmpint (pipe (fd), ==, 0);
780 /* FIXME: These should not be needed but otherwise
781 * g_unix_output_stream_writev() will block because
782 * a) the fd is writable
783 * b) writing 4x capacity will block because writes are atomic
784 * c) the fd is blocking
786 * See https://gitlab.gnome.org/GNOME/glib/issues/1654
788 g_unix_set_fd_nonblocking (fd[0], TRUE, NULL);
789 g_unix_set_fd_nonblocking (fd[1], TRUE, NULL);
791 g_assert_cmpint (fcntl (fd[0], F_SETPIPE_SZ, 4096, NULL), !=, 0);
792 retval = fcntl (fd[0], F_GETPIPE_SZ);
793 g_assert_cmpint (retval, >=, 0);
794 pipe_capacity = (gsize) retval;
795 g_assert_cmpint (pipe_capacity, >=, 4096);
797 data = g_new (guint8, 4 * pipe_capacity);
798 for (i = 0; i < 4 * pipe_capacity; i++)
800 data_read = g_new (guint8, 4 * pipe_capacity);
802 vectors[0].buffer = data;
803 vectors[0].size = 1024;
804 vectors[1].buffer = data + 1024;
805 vectors[1].size = 1024;
806 vectors[2].buffer = data + 2048;
807 vectors[2].size = 1024;
808 vectors[3].buffer = data + 3072;
809 vectors[3].size = 4 * pipe_capacity - 3072;
811 is = G_UNIX_INPUT_STREAM (g_unix_input_stream_new (fd[0], TRUE));
812 os = G_UNIX_OUTPUT_STREAM (g_unix_output_stream_new (fd[1], TRUE));
814 g_output_stream_writev_all_async (G_OUTPUT_STREAM (os),
816 G_N_ELEMENTS (vectors),
819 (GAsyncReadyCallback) writev_async_wouldblock_cb,
822 g_input_stream_read_all_async (G_INPUT_STREAM (is),
827 (GAsyncReadyCallback) read_async_wouldblock_cb,
830 while (bytes_written == 0 && bytes_read == 0)
831 g_main_context_iteration (NULL, TRUE);
833 g_assert_cmpuint (bytes_written, ==, 4 * pipe_capacity);
834 g_assert_cmpuint (bytes_read, ==, 4 * pipe_capacity);
835 g_assert_cmpmem (data_read, bytes_read, data, bytes_written);
842 #endif /* F_GETPIPE_SZ */
849 g_test_init (&argc, &argv, NULL);
851 g_test_add_func ("/unix-streams/basic", test_basic);
852 g_test_add_data_func ("/unix-streams/pipe-io-test",
853 GINT_TO_POINTER (FALSE),
855 g_test_add_data_func ("/unix-streams/nonblocking-io-test",
856 GINT_TO_POINTER (TRUE),
859 g_test_add_data_func ("/unix-streams/read_write",
860 GINT_TO_POINTER (FALSE),
863 g_test_add_data_func ("/unix-streams/read_writev",
864 GINT_TO_POINTER (TRUE),
867 g_test_add_func ("/unix-streams/write-wouldblock",
868 test_write_wouldblock);
869 g_test_add_func ("/unix-streams/writev-wouldblock",
870 test_writev_wouldblock);
872 g_test_add_func ("/unix-streams/write-async-wouldblock",
873 test_write_async_wouldblock);
874 g_test_add_func ("/unix-streams/writev-async-wouldblock",
875 test_writev_async_wouldblock);