Branch data Line data Source code
1 : : /* GLib testing framework examples and tests
2 : : * Copyright (C) 2010-2012 Collabora Ltd.
3 : : * Authors: Xavier Claessens <xclaesse@gmail.com>
4 : : * Mike Ruprecht <mike.ruprecht@collabora.co.uk>
5 : : *
6 : : * SPDX-License-Identifier: LicenseRef-old-glib-tests
7 : : *
8 : : * This work is provided "as is"; redistribution and modification
9 : : * in whole or in part, in any medium, physical or electronic is
10 : : * permitted without restriction.
11 : : *
12 : : * This work is distributed in the hope that it will be useful,
13 : : * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 : : * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
15 : : *
16 : : * In no event shall the authors or contributors be liable for any
17 : : * direct, indirect, incidental, special, exemplary, or consequential
18 : : * damages (including, but not limited to, procurement of substitute
19 : : * goods or services; loss of use, data, or profits; or business
20 : : * interruption) however caused and on any theory of liability, whether
21 : : * in contract, strict liability, or tort (including negligence or
22 : : * otherwise) arising in any way out of the use of this software, even
23 : : * if advised of the possibility of such damage.
24 : : */
25 : :
26 : : #include <glib/glib.h>
27 : : #include <glib/gstdio.h>
28 : : #include <gio/gio.h>
29 : : #include <stdlib.h>
30 : : #include <string.h>
31 : :
32 : : typedef struct
33 : : {
34 : : GInputStream parent_instance;
35 : : GBytes *bytes;
36 : : gsize offset;
37 : : gsize max_read;
38 : : guint read_count;
39 : : guint fail_read;
40 : : } TestInputStream;
41 : :
42 : : typedef GInputStreamClass TestInputStreamClass;
43 : :
44 : : static GType test_input_stream_get_type (void);
45 : :
46 : : typedef struct
47 : : {
48 : : void *buffer;
49 : : gsize count;
50 : : } TestReadData;
51 : :
52 : 12 : G_DEFINE_TYPE (TestInputStream, test_input_stream, G_TYPE_INPUT_STREAM)
53 : :
54 : : static gboolean
55 : 28 : test_input_stream_complete_read (gpointer user_data)
56 : : {
57 : 28 : GTask *task = user_data;
58 : 28 : TestInputStream *stream = g_task_get_source_object (task);
59 : 28 : TestReadData *read_data = g_task_get_task_data (task);
60 : : gsize size;
61 : 28 : gconstpointer data = g_bytes_get_data (stream->bytes, &size);
62 : : gsize count;
63 : :
64 : 28 : stream->read_count++;
65 : :
66 : 28 : if (g_task_return_error_if_cancelled (task))
67 : 2 : return G_SOURCE_REMOVE;
68 : :
69 : 26 : if (stream->fail_read == stream->read_count)
70 : : {
71 : 2 : g_task_return_new_error_literal (task, G_IO_ERROR, G_IO_ERROR_FAILED,
72 : : "Test input failure");
73 : 2 : return G_SOURCE_REMOVE;
74 : : }
75 : :
76 : 24 : count = MIN (read_data->count, stream->max_read);
77 : 24 : count = MIN (count, size - stream->offset);
78 : 24 : memcpy (read_data->buffer, (const guint8 *) data + stream->offset, count);
79 : 24 : stream->offset += count;
80 : 24 : g_task_return_int (task, count);
81 : :
82 : 24 : return G_SOURCE_REMOVE;
83 : 14 : }
84 : :
85 : : static void
86 : 28 : test_input_stream_read_async (GInputStream *stream,
87 : : void *buffer,
88 : : gsize count,
89 : : int io_priority,
90 : : GCancellable *cancellable,
91 : : GAsyncReadyCallback callback,
92 : : gpointer user_data)
93 : : {
94 : 28 : GTask *task = g_task_new (stream, cancellable, callback, user_data);
95 : 28 : TestReadData *read_data = g_new (TestReadData, 1);
96 : :
97 : 28 : read_data->buffer = buffer;
98 : 28 : read_data->count = count;
99 : 28 : g_task_set_priority (task, io_priority);
100 : 28 : g_task_set_task_data (task, read_data, g_free);
101 : 28 : g_idle_add_full (io_priority, test_input_stream_complete_read, task, g_object_unref);
102 : 28 : }
103 : :
104 : : static gssize
105 : 28 : test_input_stream_read_finish (GInputStream *stream,
106 : : GAsyncResult *result,
107 : : GError **error)
108 : : {
109 : 28 : g_assert (g_task_is_valid (result, stream));
110 : :
111 : 28 : return g_task_propagate_int (G_TASK (result), error);
112 : : }
113 : :
114 : : static void
115 : 8 : test_input_stream_finalize (GObject *object)
116 : : {
117 : 8 : TestInputStream *stream = (TestInputStream *) object;
118 : :
119 : 8 : g_clear_pointer (&stream->bytes, g_bytes_unref);
120 : 8 : G_OBJECT_CLASS (test_input_stream_parent_class)->finalize (object);
121 : 8 : }
122 : :
123 : : static void
124 : 2 : test_input_stream_class_init (TestInputStreamClass *stream_class)
125 : : {
126 : 2 : GObjectClass *object_class = G_OBJECT_CLASS (stream_class);
127 : 2 : GInputStreamClass *input_stream_class = G_INPUT_STREAM_CLASS (stream_class);
128 : :
129 : 2 : object_class->finalize = test_input_stream_finalize;
130 : 2 : input_stream_class->read_async = test_input_stream_read_async;
131 : 2 : input_stream_class->read_finish = test_input_stream_read_finish;
132 : 2 : }
133 : :
134 : : static void
135 : 8 : test_input_stream_init (TestInputStream *stream)
136 : : {
137 : 8 : stream->max_read = G_MAXSIZE;
138 : 8 : }
139 : :
140 : : static TestInputStream *
141 : 8 : test_input_stream_new (GBytes *bytes)
142 : : {
143 : 8 : TestInputStream *stream = g_object_new (test_input_stream_get_type (), NULL);
144 : :
145 : 8 : stream->bytes = g_bytes_ref (bytes);
146 : :
147 : 8 : return stream;
148 : : }
149 : :
150 : : typedef struct
151 : : {
152 : : GOutputStream parent_instance;
153 : : TestInputStream *input;
154 : : GByteArray *bytes;
155 : : gsize max_write;
156 : : guint write_count;
157 : : guint fail_write;
158 : : guint delay_ms;
159 : : gboolean cancel_on_write;
160 : : gboolean saw_overlap;
161 : : } TestOutputStream;
162 : :
163 : : typedef GOutputStreamClass TestOutputStreamClass;
164 : :
165 : : static GType test_output_stream_get_type (void);
166 : :
167 : 12 : G_DEFINE_TYPE (TestOutputStream, test_output_stream, G_TYPE_OUTPUT_STREAM)
168 : :
169 : : static gboolean
170 : 392 : test_output_stream_complete_write (gpointer user_data)
171 : : {
172 : 392 : GTask *task = user_data;
173 : 392 : TestOutputStream *stream = g_task_get_source_object (task);
174 : 392 : GBytes *bytes = g_task_get_task_data (task);
175 : : gsize size;
176 : 392 : gconstpointer data = g_bytes_get_data (bytes, &size);
177 : :
178 : 392 : if (stream->input->read_count >= 2)
179 : 390 : stream->saw_overlap = TRUE;
180 : :
181 : 392 : if (g_task_return_error_if_cancelled (task))
182 : 2 : return G_SOURCE_REMOVE;
183 : :
184 : 390 : if (stream->fail_write == stream->write_count)
185 : : {
186 : 2 : g_task_return_new_error_literal (task, G_IO_ERROR, G_IO_ERROR_FAILED,
187 : : "Test output failure");
188 : 2 : return G_SOURCE_REMOVE;
189 : : }
190 : :
191 : 388 : g_byte_array_append (stream->bytes, data, size);
192 : 388 : g_task_return_int (task, size);
193 : :
194 : 388 : return G_SOURCE_REMOVE;
195 : 196 : }
196 : :
197 : : static void
198 : 392 : test_output_stream_write_async (GOutputStream *stream,
199 : : const void *buffer,
200 : : gsize count,
201 : : int io_priority,
202 : : GCancellable *cancellable,
203 : : GAsyncReadyCallback callback,
204 : : gpointer user_data)
205 : : {
206 : 392 : TestOutputStream *test_stream = (TestOutputStream *) stream;
207 : 392 : GTask *task = g_task_new (stream, cancellable, callback, user_data);
208 : : GBytes *bytes;
209 : :
210 : 392 : count = MIN (count, test_stream->max_write);
211 : 392 : bytes = g_bytes_new (buffer, count);
212 : 392 : test_stream->write_count++;
213 : 392 : g_task_set_priority (task, io_priority);
214 : 392 : g_task_set_task_data (task, bytes, (GDestroyNotify) g_bytes_unref);
215 : :
216 : 392 : if (test_stream->cancel_on_write)
217 : 2 : g_cancellable_cancel (cancellable);
218 : :
219 : 392 : if (test_stream->delay_ms > 0)
220 : 585 : g_timeout_add_full (io_priority, test_stream->delay_ms,
221 : 195 : test_output_stream_complete_write, task, g_object_unref);
222 : : else
223 : 2 : g_idle_add_full (io_priority, test_output_stream_complete_write, task, g_object_unref);
224 : 392 : }
225 : :
226 : : static gssize
227 : 392 : test_output_stream_write_finish (GOutputStream *stream,
228 : : GAsyncResult *result,
229 : : GError **error)
230 : : {
231 : 392 : g_assert (g_task_is_valid (result, stream));
232 : :
233 : 392 : return g_task_propagate_int (G_TASK (result), error);
234 : : }
235 : :
236 : : static void
237 : 8 : test_output_stream_finalize (GObject *object)
238 : : {
239 : 8 : TestOutputStream *stream = (TestOutputStream *) object;
240 : :
241 : 8 : g_clear_object (&stream->input);
242 : 8 : g_clear_pointer (&stream->bytes, g_byte_array_unref);
243 : 8 : G_OBJECT_CLASS (test_output_stream_parent_class)->finalize (object);
244 : 8 : }
245 : :
246 : : static void
247 : 2 : test_output_stream_class_init (TestOutputStreamClass *stream_class)
248 : : {
249 : 2 : GObjectClass *object_class = G_OBJECT_CLASS (stream_class);
250 : 2 : GOutputStreamClass *output_stream_class = G_OUTPUT_STREAM_CLASS (stream_class);
251 : :
252 : 2 : object_class->finalize = test_output_stream_finalize;
253 : 2 : output_stream_class->write_async = test_output_stream_write_async;
254 : 2 : output_stream_class->write_finish = test_output_stream_write_finish;
255 : 2 : }
256 : :
257 : : static void
258 : 8 : test_output_stream_init (TestOutputStream *stream)
259 : : {
260 : 8 : stream->bytes = g_byte_array_new ();
261 : 8 : stream->max_write = G_MAXSIZE;
262 : 8 : }
263 : :
264 : : static TestOutputStream *
265 : 8 : test_output_stream_new (TestInputStream *input)
266 : : {
267 : 8 : TestOutputStream *stream = g_object_new (test_output_stream_get_type (), NULL);
268 : :
269 : 8 : stream->input = g_object_ref (input);
270 : :
271 : 8 : return stream;
272 : : }
273 : :
274 : : typedef enum
275 : : {
276 : : TEST_THREADED_NONE = 0,
277 : : TEST_THREADED_ISTREAM = 1,
278 : : TEST_THREADED_OSTREAM = 2,
279 : : TEST_CANCEL = 4,
280 : : TEST_THREADED_BOTH = TEST_THREADED_ISTREAM | TEST_THREADED_OSTREAM,
281 : : } TestThreadedFlags;
282 : :
283 : : typedef struct
284 : : {
285 : : GMainLoop *main_loop;
286 : : gchar *data;
287 : : gsize data_len;
288 : : GInputStream *istream;
289 : : GOutputStream *ostream;
290 : : TestThreadedFlags flags;
291 : : gchar *input_path;
292 : : gchar *output_path;
293 : : } TestCopyChunksData;
294 : :
295 : : static void
296 : 12 : test_copy_chunks_splice_cb (GObject *source,
297 : : GAsyncResult *res,
298 : : gpointer user_data)
299 : : {
300 : 12 : TestCopyChunksData *data = user_data;
301 : : gchar *received_data;
302 : 12 : GError *error = NULL;
303 : : gssize bytes_spliced;
304 : :
305 : 18 : bytes_spliced = g_output_stream_splice_finish (G_OUTPUT_STREAM (source),
306 : 6 : res, &error);
307 : :
308 : 12 : if (data->flags & TEST_CANCEL)
309 : : {
310 : 2 : g_assert_error (error, G_IO_ERROR, G_IO_ERROR_CANCELLED);
311 : 2 : g_error_free (error);
312 : 2 : g_main_loop_quit (data->main_loop);
313 : 2 : return;
314 : : }
315 : :
316 : 10 : g_assert_no_error (error);
317 : 10 : g_assert_cmpint (bytes_spliced, ==, data->data_len);
318 : :
319 : 10 : if (data->flags & TEST_THREADED_OSTREAM)
320 : : {
321 : 6 : gsize length = 0;
322 : :
323 : 6 : g_file_get_contents (data->output_path, &received_data,
324 : : &length, &error);
325 : 6 : g_assert_no_error (error);
326 : 6 : g_assert_cmpuint (length, ==, data->data_len);
327 : 9 : g_assert_cmpmem (received_data, length, data->data, data->data_len);
328 : 6 : g_free (received_data);
329 : 3 : }
330 : : else
331 : : {
332 : 4 : received_data = g_memory_output_stream_get_data (G_MEMORY_OUTPUT_STREAM (data->ostream));
333 : 6 : g_assert_cmpuint (g_memory_output_stream_get_data_size (G_MEMORY_OUTPUT_STREAM (data->ostream)),
334 : 4 : ==, data->data_len);
335 : 6 : g_assert_cmpmem (received_data, data->data_len, data->data, data->data_len);
336 : : }
337 : :
338 : 10 : g_assert (g_input_stream_is_closed (data->istream));
339 : 10 : g_assert (g_output_stream_is_closed (data->ostream));
340 : :
341 : 10 : if (data->flags & TEST_THREADED_ISTREAM)
342 : : {
343 : 4 : g_unlink (data->input_path);
344 : 4 : g_free (data->input_path);
345 : 2 : }
346 : :
347 : 10 : if (data->flags & TEST_THREADED_OSTREAM)
348 : : {
349 : 6 : g_unlink (data->output_path);
350 : 6 : g_free (data->output_path);
351 : 3 : }
352 : :
353 : 10 : g_main_loop_quit (data->main_loop);
354 : 6 : }
355 : :
356 : : static void
357 : 12 : test_copy_chunks_start (TestThreadedFlags flags,
358 : : gsize data_len)
359 : : {
360 : : TestCopyChunksData data;
361 : 12 : GError *error = NULL;
362 : 12 : GCancellable *cancellable = NULL;
363 : :
364 : 12 : data.main_loop = g_main_loop_new (NULL, FALSE);
365 : 12 : data.data = g_malloc (data_len);
366 : 12 : data.data_len = data_len;
367 : 12 : data.flags = flags;
368 : :
369 : 4194610 : for (gsize i = 0; i < data_len; i++)
370 : 4194598 : data.data[i] = 'a' + (i % 26);
371 : :
372 : 12 : if (data.flags & TEST_CANCEL)
373 : : {
374 : 2 : cancellable = g_cancellable_new ();
375 : 2 : g_cancellable_cancel (cancellable);
376 : 1 : }
377 : :
378 : 12 : if (data.flags & TEST_THREADED_ISTREAM)
379 : : {
380 : : GFile *file;
381 : : GFileIOStream *stream;
382 : :
383 : 4 : file = g_file_new_tmp ("test-inputXXXXXX", &stream, &error);
384 : 4 : g_assert_no_error (error);
385 : 4 : g_object_unref (stream);
386 : 4 : data.input_path = g_file_get_path (file);
387 : 6 : g_file_set_contents (data.input_path,
388 : 4 : data.data, data.data_len,
389 : : &error);
390 : 4 : g_assert_no_error (error);
391 : 4 : data.istream = G_INPUT_STREAM (g_file_read (file, NULL, &error));
392 : 4 : g_assert_no_error (error);
393 : 4 : g_object_unref (file);
394 : 2 : }
395 : : else
396 : : {
397 : 8 : data.istream = g_memory_input_stream_new_from_data (data.data, data.data_len, NULL);
398 : : }
399 : :
400 : 12 : if (data.flags & TEST_THREADED_OSTREAM)
401 : : {
402 : : GFile *file;
403 : : GFileIOStream *stream;
404 : :
405 : 6 : file = g_file_new_tmp ("test-outputXXXXXX", &stream, &error);
406 : 6 : g_assert_no_error (error);
407 : 6 : g_object_unref (stream);
408 : 6 : data.output_path = g_file_get_path (file);
409 : 6 : data.ostream = G_OUTPUT_STREAM (g_file_replace (file, NULL, FALSE,
410 : : G_FILE_CREATE_NONE,
411 : : NULL, &error));
412 : 6 : g_assert_no_error (error);
413 : 6 : g_object_unref (file);
414 : 3 : }
415 : : else
416 : : {
417 : 6 : data.ostream = g_memory_output_stream_new (NULL, 0, g_realloc, g_free);
418 : : }
419 : :
420 : 18 : g_output_stream_splice_async (data.ostream, data.istream,
421 : : G_OUTPUT_STREAM_SPLICE_CLOSE_SOURCE |
422 : : G_OUTPUT_STREAM_SPLICE_CLOSE_TARGET,
423 : 6 : G_PRIORITY_DEFAULT, cancellable,
424 : : test_copy_chunks_splice_cb, &data);
425 : :
426 : : /* We do not hold a ref in data struct, this is to make sure the operation
427 : : * keeps the iostream objects alive until it finishes
428 : : */
429 : 12 : g_object_unref (data.istream);
430 : 12 : g_object_unref (data.ostream);
431 : 12 : g_clear_object (&cancellable);
432 : :
433 : 12 : g_main_loop_run (data.main_loop);
434 : 12 : g_main_loop_unref (data.main_loop);
435 : 12 : g_free (data.data);
436 : 12 : }
437 : :
438 : : static void
439 : 2 : test_copy_chunks (void)
440 : : {
441 : 2 : test_copy_chunks_start (TEST_THREADED_NONE, 26);
442 : 2 : }
443 : :
444 : : static void
445 : 2 : test_copy_chunks_threaded_input (void)
446 : : {
447 : 2 : test_copy_chunks_start (TEST_THREADED_ISTREAM, 26);
448 : 2 : }
449 : :
450 : : static void
451 : 2 : test_copy_chunks_threaded_output (void)
452 : : {
453 : 2 : test_copy_chunks_start (TEST_THREADED_OSTREAM, 26);
454 : 2 : }
455 : :
456 : : static void
457 : 2 : test_copy_chunks_threaded (void)
458 : : {
459 : 2 : test_copy_chunks_start (TEST_THREADED_BOTH, 26);
460 : 2 : }
461 : :
462 : : static void
463 : 2 : test_copy_chunks_large_threaded_output (void)
464 : : {
465 : 2 : test_copy_chunks_start (TEST_THREADED_OSTREAM, 2 * 1024 * 1024 + 17);
466 : 2 : }
467 : :
468 : : static void
469 : 2 : test_cancelled (void)
470 : : {
471 : 2 : test_copy_chunks_start (TEST_THREADED_NONE | TEST_CANCEL, 26);
472 : 2 : }
473 : :
474 : : typedef struct
475 : : {
476 : : GMainLoop *loop;
477 : : GError *error;
478 : : gssize bytes_spliced;
479 : : } TestPipelineResult;
480 : :
481 : : static void
482 : 8 : test_pipeline_splice_cb (GObject *source,
483 : : GAsyncResult *result,
484 : : gpointer user_data)
485 : : {
486 : 8 : TestPipelineResult *test_result = user_data;
487 : :
488 : 8 : test_result->bytes_spliced =
489 : 8 : g_output_stream_splice_finish (G_OUTPUT_STREAM (source), result, &test_result->error);
490 : 8 : g_main_loop_quit (test_result->loop);
491 : 8 : }
492 : :
493 : : static GBytes *
494 : 10 : test_pipeline_create_bytes (gsize size)
495 : : {
496 : 10 : guint8 *data = g_malloc (size);
497 : :
498 : 7340110 : for (gsize i = 0; i < size; i++)
499 : 7340100 : data[i] = i % 251;
500 : :
501 : 10 : return g_bytes_new_take (data, size);
502 : : }
503 : :
504 : : static void
505 : 2 : test_sync_splice_large (void)
506 : : {
507 : 2 : GBytes *bytes = test_pipeline_create_bytes (2 * 1024 * 1024 + 17);
508 : 2 : GInputStream *input = g_memory_input_stream_new_from_bytes (bytes);
509 : 2 : GOutputStream *output = g_memory_output_stream_new_resizable ();
510 : 2 : GError *error = NULL;
511 : : gsize size;
512 : 2 : gconstpointer data = g_bytes_get_data (bytes, &size);
513 : : gssize bytes_spliced;
514 : :
515 : 2 : bytes_spliced = g_output_stream_splice (output, input,
516 : : (G_OUTPUT_STREAM_SPLICE_CLOSE_SOURCE |
517 : : G_OUTPUT_STREAM_SPLICE_CLOSE_TARGET),
518 : : NULL, &error);
519 : :
520 : 2 : g_assert_no_error (error);
521 : 2 : g_assert_cmpint (bytes_spliced, ==, size);
522 : 3 : g_assert_cmpuint (g_memory_output_stream_get_data_size (G_MEMORY_OUTPUT_STREAM (output)),
523 : 2 : ==, size);
524 : 3 : g_assert_cmpmem (g_memory_output_stream_get_data (G_MEMORY_OUTPUT_STREAM (output)), size,
525 : 2 : data, size);
526 : 2 : g_assert_true (g_input_stream_is_closed (input));
527 : 2 : g_assert_true (g_output_stream_is_closed (output));
528 : :
529 : 2 : g_object_unref (output);
530 : 2 : g_object_unref (input);
531 : 2 : g_bytes_unref (bytes);
532 : 2 : }
533 : :
534 : : static TestPipelineResult
535 : 8 : test_pipeline_run (TestInputStream *input,
536 : : TestOutputStream *output,
537 : : GOutputStreamSpliceFlags flags,
538 : : GCancellable *cancellable)
539 : : {
540 : 8 : TestPipelineResult result = { 0, };
541 : :
542 : 8 : result.loop = g_main_loop_new (NULL, FALSE);
543 : 8 : result.bytes_spliced = -1;
544 : 12 : g_output_stream_splice_async (G_OUTPUT_STREAM (output),
545 : 8 : G_INPUT_STREAM (input),
546 : 4 : flags,
547 : : G_PRIORITY_DEFAULT,
548 : 4 : cancellable,
549 : : test_pipeline_splice_cb,
550 : : &result);
551 : 8 : g_main_loop_run (result.loop);
552 : 8 : g_main_loop_unref (result.loop);
553 : 8 : result.loop = NULL;
554 : :
555 : 8 : return result;
556 : : }
557 : :
558 : : static void
559 : 2 : test_pipeline_overlap_partial_writes (void)
560 : : {
561 : 2 : GBytes *bytes = test_pipeline_create_bytes (768 * 1024 + 17);
562 : 2 : TestInputStream *input = test_input_stream_new (bytes);
563 : 2 : TestOutputStream *output = test_output_stream_new (input);
564 : : TestPipelineResult result;
565 : : gsize size;
566 : 2 : gconstpointer data = g_bytes_get_data (bytes, &size);
567 : :
568 : 2 : input->max_read = 128 * 1024;
569 : 2 : output->max_write = 4096;
570 : 2 : output->delay_ms = 1;
571 : 2 : result = test_pipeline_run (input, output, G_OUTPUT_STREAM_SPLICE_NONE, NULL);
572 : :
573 : 2 : g_assert_no_error (result.error);
574 : 2 : g_assert_cmpint (result.bytes_spliced, ==, size);
575 : 2 : g_assert_true (output->saw_overlap);
576 : 3 : g_assert_cmpmem (output->bytes->data, output->bytes->len, data, size);
577 : 2 : g_assert_false (g_input_stream_is_closed (G_INPUT_STREAM (input)));
578 : 2 : g_assert_false (g_output_stream_is_closed (G_OUTPUT_STREAM (output)));
579 : :
580 : 2 : g_object_unref (output);
581 : 2 : g_object_unref (input);
582 : 2 : g_bytes_unref (bytes);
583 : 2 : }
584 : :
585 : : static void
586 : 2 : test_pipeline_read_error_during_write (void)
587 : : {
588 : 2 : GBytes *bytes = test_pipeline_create_bytes (256 * 1024);
589 : 2 : TestInputStream *input = test_input_stream_new (bytes);
590 : 2 : TestOutputStream *output = test_output_stream_new (input);
591 : : TestPipelineResult result;
592 : :
593 : 2 : input->max_read = 64 * 1024;
594 : 2 : input->fail_read = 2;
595 : 2 : output->delay_ms = 10;
596 : 2 : result = test_pipeline_run (input, output,
597 : : (G_OUTPUT_STREAM_SPLICE_CLOSE_SOURCE |
598 : : G_OUTPUT_STREAM_SPLICE_CLOSE_TARGET),
599 : : NULL);
600 : :
601 : 2 : g_assert_error (result.error, G_IO_ERROR, G_IO_ERROR_FAILED);
602 : 2 : g_assert_cmpstr (result.error->message, ==, "Test input failure");
603 : 2 : g_assert_true (g_input_stream_is_closed (G_INPUT_STREAM (input)));
604 : 2 : g_assert_true (g_output_stream_is_closed (G_OUTPUT_STREAM (output)));
605 : 2 : g_clear_error (&result.error);
606 : :
607 : 2 : g_object_unref (output);
608 : 2 : g_object_unref (input);
609 : 2 : g_bytes_unref (bytes);
610 : 2 : }
611 : :
612 : : static void
613 : 2 : test_pipeline_write_error_during_read (void)
614 : : {
615 : 2 : GBytes *bytes = test_pipeline_create_bytes (256 * 1024);
616 : 2 : TestInputStream *input = test_input_stream_new (bytes);
617 : 2 : TestOutputStream *output = test_output_stream_new (input);
618 : : TestPipelineResult result;
619 : :
620 : 2 : input->max_read = 64 * 1024;
621 : 2 : output->fail_write = 1;
622 : 2 : output->delay_ms = 1;
623 : 2 : result = test_pipeline_run (input, output,
624 : : G_OUTPUT_STREAM_SPLICE_CLOSE_SOURCE,
625 : : NULL);
626 : :
627 : 2 : g_assert_error (result.error, G_IO_ERROR, G_IO_ERROR_FAILED);
628 : 2 : g_assert_cmpstr (result.error->message, ==, "Test output failure");
629 : 2 : g_assert_true (g_input_stream_is_closed (G_INPUT_STREAM (input)));
630 : 2 : g_assert_false (g_output_stream_is_closed (G_OUTPUT_STREAM (output)));
631 : 2 : g_clear_error (&result.error);
632 : :
633 : 2 : g_object_unref (output);
634 : 2 : g_object_unref (input);
635 : 2 : g_bytes_unref (bytes);
636 : 2 : }
637 : :
638 : : static void
639 : 2 : test_pipeline_cancel_during_overlap (void)
640 : : {
641 : 2 : GBytes *bytes = test_pipeline_create_bytes (256 * 1024);
642 : 2 : TestInputStream *input = test_input_stream_new (bytes);
643 : 2 : TestOutputStream *output = test_output_stream_new (input);
644 : 2 : GCancellable *cancellable = g_cancellable_new ();
645 : : TestPipelineResult result;
646 : :
647 : 2 : input->max_read = 64 * 1024;
648 : 2 : output->cancel_on_write = TRUE;
649 : 3 : result = test_pipeline_run (input, output,
650 : : G_OUTPUT_STREAM_SPLICE_CLOSE_TARGET,
651 : 1 : cancellable);
652 : :
653 : 2 : g_assert_error (result.error, G_IO_ERROR, G_IO_ERROR_CANCELLED);
654 : 2 : g_assert_false (g_input_stream_is_closed (G_INPUT_STREAM (input)));
655 : 2 : g_assert_true (g_output_stream_is_closed (G_OUTPUT_STREAM (output)));
656 : 2 : g_clear_error (&result.error);
657 : :
658 : 2 : g_object_unref (cancellable);
659 : 2 : g_object_unref (output);
660 : 2 : g_object_unref (input);
661 : 2 : g_bytes_unref (bytes);
662 : 2 : }
663 : :
664 : : int
665 : 2 : main (int argc,
666 : : char *argv[])
667 : : {
668 : 2 : g_test_init (&argc, &argv, NULL);
669 : :
670 : 2 : g_test_add_func ("/async-splice/copy-chunks", test_copy_chunks);
671 : 2 : g_test_add_func ("/async-splice/copy-chunks-threaded-input",
672 : : test_copy_chunks_threaded_input);
673 : 2 : g_test_add_func ("/async-splice/copy-chunks-threaded-output",
674 : : test_copy_chunks_threaded_output);
675 : 2 : g_test_add_func ("/async-splice/copy-chunks-threaded",
676 : : test_copy_chunks_threaded);
677 : 2 : g_test_add_func ("/async-splice/copy-chunks-large-threaded-output",
678 : : test_copy_chunks_large_threaded_output);
679 : 2 : g_test_add_func ("/async-splice/cancelled",
680 : : test_cancelled);
681 : 2 : g_test_add_func ("/async-splice/sync-large",
682 : : test_sync_splice_large);
683 : 2 : g_test_add_func ("/async-splice/pipeline/overlap-partial-writes",
684 : : test_pipeline_overlap_partial_writes);
685 : 2 : g_test_add_func ("/async-splice/pipeline/read-error-during-write",
686 : : test_pipeline_read_error_during_write);
687 : 2 : g_test_add_func ("/async-splice/pipeline/write-error-during-read",
688 : : test_pipeline_write_error_during_read);
689 : 2 : g_test_add_func ("/async-splice/pipeline/cancel-during-overlap",
690 : : test_pipeline_cancel_during_overlap);
691 : :
692 : 2 : return g_test_run();
693 : : }
|