Branch data Line data Source code
1 : : /*
2 : : * Copyright © 2014 Canonical Limited
3 : : *
4 : : * SPDX-License-Identifier: LGPL-2.1-or-later
5 : : *
6 : : * This library is free software; you can redistribute it and/or
7 : : * modify it under the terms of the GNU Lesser General Public
8 : : * License as published by the Free Software Foundation; either
9 : : * version 2.1 of the License, or (at your option) any later version.
10 : : *
11 : : * This library is distributed in the hope that it will be useful,
12 : : * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 : : * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 : : * Lesser General Public License for more details.
15 : : *
16 : : * You should have received a copy of the GNU Lesser General
17 : : * Public License along with this library; if not, see <http://www.gnu.org/licenses/>.
18 : : *
19 : : * Authors: Ryan Lortie <desrt@desrt.ca>
20 : : */
21 : :
22 : : #include <gio/gio.h>
23 : : #include <string.h>
24 : :
25 : : static gboolean expected_read_success;
26 : : static guint expected_read;
27 : : static gboolean got_read_done;
28 : :
29 : : static void
30 : 6 : read_done (GObject *source,
31 : : GAsyncResult *result,
32 : : gpointer user_data)
33 : : {
34 : : gboolean success;
35 : : gsize read;
36 : :
37 : 6 : success = g_input_stream_read_all_finish (G_INPUT_STREAM (source), result, &read, NULL);
38 : 6 : g_assert_cmpint (expected_read_success, ==, success);
39 : 6 : g_assert_cmpint (expected_read, ==, read);
40 : 6 : got_read_done = TRUE;
41 : 6 : }
42 : :
43 : : static void
44 : 6 : wait_for_read (gboolean success,
45 : : gsize read)
46 : : {
47 : 6 : g_assert_false (got_read_done);
48 : 6 : expected_read_success = success;
49 : 6 : expected_read = read;
50 : :
51 : 14 : while (!got_read_done)
52 : 8 : g_main_context_iteration (NULL, TRUE);
53 : :
54 : 6 : got_read_done = FALSE;
55 : 6 : }
56 : :
57 : : static gboolean expected_write_success;
58 : : static guint expected_written;
59 : : static gboolean got_write_done;
60 : :
61 : : static void
62 : 6 : write_done (GObject *source,
63 : : GAsyncResult *result,
64 : : gpointer user_data)
65 : : {
66 : : gboolean success;
67 : : gsize written;
68 : :
69 : 6 : success = g_output_stream_write_all_finish (G_OUTPUT_STREAM (source), result, &written, NULL);
70 : 6 : g_assert_cmpint (expected_write_success, ==, success);
71 : 6 : g_assert_cmpint (expected_written, ==, written);
72 : 6 : got_write_done = TRUE;
73 : 6 : }
74 : :
75 : : static void
76 : 6 : wait_for_write (gboolean success,
77 : : gsize written)
78 : : {
79 : 6 : g_assert_false (got_write_done);
80 : 6 : expected_write_success = success;
81 : 6 : expected_written = written;
82 : :
83 : 16 : while (!got_write_done)
84 : 10 : g_main_context_iteration (NULL, TRUE);
85 : :
86 : 6 : got_write_done = FALSE;
87 : 6 : }
88 : :
89 : : static void
90 : 1 : test_write_all_async_memory (void)
91 : : {
92 : : GOutputStream *ms;
93 : : gchar b[24];
94 : :
95 : 1 : ms = g_memory_output_stream_new (b, sizeof b, NULL, NULL);
96 : :
97 : 1 : g_output_stream_write_all_async (ms, "0123456789", 10, 0, NULL, write_done, NULL);
98 : 1 : wait_for_write (TRUE, 10);
99 : :
100 : 1 : g_output_stream_write_all_async (ms, "0123456789", 10, 0, NULL, write_done, NULL);
101 : 1 : wait_for_write (TRUE, 10);
102 : :
103 : : /* this will trigger an out-of-space error, but we will see the
104 : : * partial write...
105 : : */
106 : 1 : g_output_stream_write_all_async (ms, "0123456789", 10, 0, NULL, write_done, NULL);
107 : 1 : wait_for_write (FALSE, 4);
108 : :
109 : : /* and still an error, but no further bytes written */
110 : 1 : g_output_stream_write_all_async (ms, "0123456789", 10, 0, NULL, write_done, NULL);
111 : 1 : wait_for_write (FALSE, 0);
112 : :
113 : 1 : g_assert_cmpint (memcmp (b, "012345678901234567890123", 24), ==, 0);
114 : :
115 : 1 : g_object_unref (ms);
116 : 1 : }
117 : :
118 : : static void
119 : 1 : test_read_all_async_memory (void)
120 : : {
121 : : GInputStream *ms;
122 : 1 : gchar b[24] = "0123456789ABCDEFGHIJ!@#$";
123 : : gchar buf[10];
124 : :
125 : 1 : ms = g_memory_input_stream_new_from_data (b, sizeof b, NULL);
126 : :
127 : 1 : g_input_stream_read_all_async (ms, buf, 10, 0, NULL, read_done, NULL);
128 : 1 : wait_for_read (TRUE, 10);
129 : 1 : g_assert_cmpint (memcmp (buf, "0123456789", 10), ==, 0);
130 : :
131 : 1 : g_input_stream_read_all_async (ms, buf, 10, 0, NULL, read_done, NULL);
132 : 1 : wait_for_read (TRUE, 10);
133 : 1 : g_assert_cmpint (memcmp (buf, "ABCDEFGHIJ", 10), ==, 0);
134 : :
135 : : /* partial read... */
136 : 1 : g_input_stream_read_all_async (ms, buf, 10, 0, NULL, read_done, NULL);
137 : 1 : wait_for_read (TRUE, 4);
138 : 1 : g_assert_cmpint (memcmp (buf, "!@#$", 4), ==, 0);
139 : :
140 : : /* EOF */
141 : 1 : g_input_stream_read_all_async (ms, buf, 10, 0, NULL, read_done, NULL);
142 : 1 : wait_for_read (TRUE, 0);
143 : :
144 : 1 : g_object_unref (ms);
145 : 1 : }
146 : :
147 : : #ifdef G_OS_UNIX
148 : : #include <errno.h>
149 : : #include <glib-unix.h>
150 : : #include <sys/types.h>
151 : : #include <sys/socket.h>
152 : : #include <gio/gunixinputstream.h>
153 : : #include <gio/gunixoutputstream.h>
154 : :
155 : : static void
156 : 1 : test_read_write_all_async_pipe (void)
157 : : {
158 : : GCancellable *cancellable;
159 : 1 : GError *error = NULL;
160 : : GOutputStream *out;
161 : : GInputStream *in;
162 : : gsize in_flight;
163 : : gsize s;
164 : 1 : gchar wbuf[100] = { 0, };
165 : : gchar rbuf[100];
166 : :
167 : : {
168 : : gint sv[2];
169 : :
170 : 1 : g_unix_open_pipe (sv, O_CLOEXEC | O_NONBLOCK, &error);
171 : 1 : g_assert_no_error (error);
172 : :
173 : 1 : out = g_unix_output_stream_new (sv[1], TRUE);
174 : 1 : in = g_unix_input_stream_new (sv[0], TRUE);
175 : : }
176 : :
177 : : /* Try to fill up the buffer */
178 : 1 : in_flight = 0;
179 : 602 : while (g_pollable_output_stream_is_writable (G_POLLABLE_OUTPUT_STREAM (out)))
180 : : {
181 : 601 : s = g_output_stream_write (out, wbuf, sizeof wbuf, NULL, &error);
182 : 601 : g_assert_no_error (error);
183 : 601 : g_assert_cmpint (s, >, 0);
184 : 601 : in_flight += s;
185 : : }
186 : :
187 : : /* Now start a blocking write_all; nothing should happen. */
188 : 1 : cancellable = g_cancellable_new ();
189 : 1 : g_output_stream_write_all_async (out, "0123456789", 10, 0, cancellable, write_done, NULL);
190 : 1 : while (g_main_context_iteration (NULL, FALSE))
191 : : ;
192 : 1 : g_assert_false (got_write_done);
193 : :
194 : : /* Cancel that to make sure it works */
195 : 1 : g_cancellable_cancel (cancellable);
196 : 1 : g_object_unref (cancellable);
197 : 1 : wait_for_write (FALSE, 0);
198 : :
199 : : /* Start it again */
200 : 1 : g_output_stream_write_all_async (out, "0123456789", 10, 0, NULL, write_done, NULL);
201 : 1 : while (g_main_context_iteration (NULL, FALSE))
202 : : ;
203 : 1 : g_assert_false (got_write_done);
204 : :
205 : : /* Now drain as much as we originally put in the buffer to make it
206 : : * block -- this will unblock the writer.
207 : : */
208 : 602 : while (in_flight)
209 : : {
210 : 601 : s = g_input_stream_read (in, rbuf, MIN (sizeof wbuf, in_flight), NULL, &error);
211 : 601 : g_assert_no_error (error);
212 : 601 : g_assert_cmpint (s, >, 0);
213 : 601 : in_flight -= s;
214 : : }
215 : :
216 : : /* That will have caused some writing to start happening. Do a
217 : : * read_all as well, for more bytes than was written.
218 : : */
219 : 1 : g_input_stream_read_all_async (in, rbuf, sizeof rbuf, 0, NULL, read_done, NULL);
220 : :
221 : : /* The write is surely finished by now */
222 : 1 : wait_for_write (TRUE, 10);
223 : : /* ...but the read will not yet be satisfied */
224 : 1 : g_assert_false (got_read_done);
225 : :
226 : : /* Feed the read more than it asked for; this really should not block
227 : : * since the buffer is so small...
228 : : */
229 : 1 : g_output_stream_write_all (out, wbuf, sizeof wbuf, 0, NULL, &error);
230 : 1 : g_assert_no_error (error);
231 : :
232 : : /* Read will have finished now */
233 : 1 : wait_for_read (TRUE, sizeof rbuf);
234 : :
235 : : /* Close the writer end to make an EOF condition */
236 : 1 : g_output_stream_close (out, NULL, NULL);
237 : :
238 : : /* ... and we should have exactly 10 extra bytes left in the buffer */
239 : 1 : g_input_stream_read_all_async (in, rbuf, sizeof rbuf, 0, NULL, read_done, NULL);
240 : 1 : wait_for_read (TRUE, 10);
241 : :
242 : 1 : g_object_unref (out);
243 : 1 : g_object_unref (in);
244 : 1 : }
245 : : #endif
246 : :
247 : : int
248 : 1 : main (int argc,
249 : : char **argv)
250 : : {
251 : 1 : g_test_init (&argc, &argv, NULL);
252 : :
253 : 1 : g_test_add_func ("/stream/read_all_async/memory", test_read_all_async_memory);
254 : 1 : g_test_add_func ("/stream/write_all_async/memory", test_write_all_async_memory);
255 : : #ifdef G_OS_UNIX
256 : 1 : g_test_add_func ("/stream/read_write_all_async/pipe", test_read_write_all_async_pipe);
257 : : #endif
258 : :
259 : 1 : return g_test_run();
260 : : }
|