glib/gio/tests/async-splice-output-stream.c
Carlos Garnacho cf85241aba tests: Add splice cancellation test
This doesn't trigger the cancellation assertion issue when run locally
(the task didn't return yet, so the error is simply overwritten), but
perhaps it ever does in CI. Anyhow, it's good to have a cancellation
test.
2020-08-28 11:38:51 +02:00

231 lines
6.5 KiB
C

/* GLib testing framework examples and tests
* Copyright (C) 2010-2012 Collabora Ltd.
* Authors: Xavier Claessens <xclaesse@gmail.com>
* Mike Ruprecht <mike.ruprecht@collabora.co.uk>
*
* This work is provided "as is"; redistribution and modification
* in whole or in part, in any medium, physical or electronic is
* permitted without restriction.
*
* This work is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
*
* In no event shall the authors or contributors be liable for any
* direct, indirect, incidental, special, exemplary, or consequential
* damages (including, but not limited to, procurement of substitute
* goods or services; loss of use, data, or profits; or business
* interruption) however caused and on any theory of liability, whether
* in contract, strict liability, or tort (including negligence or
* otherwise) arising in any way out of the use of this software, even
* if advised of the possibility of such damage.
*/
#include <glib/glib.h>
#include <glib/gstdio.h>
#include <gio/gio.h>
#include <stdlib.h>
#include <string.h>
typedef enum
{
TEST_THREADED_NONE = 0,
TEST_THREADED_ISTREAM = 1,
TEST_THREADED_OSTREAM = 2,
TEST_CANCEL = 4,
TEST_THREADED_BOTH = TEST_THREADED_ISTREAM | TEST_THREADED_OSTREAM,
} TestThreadedFlags;
typedef struct
{
GMainLoop *main_loop;
const gchar *data;
GInputStream *istream;
GOutputStream *ostream;
TestThreadedFlags flags;
gchar *input_path;
gchar *output_path;
} TestCopyChunksData;
static void
test_copy_chunks_splice_cb (GObject *source,
GAsyncResult *res,
gpointer user_data)
{
TestCopyChunksData *data = user_data;
gchar *received_data;
GError *error = NULL;
gssize bytes_spliced;
bytes_spliced = g_output_stream_splice_finish (G_OUTPUT_STREAM (source),
res, &error);
if (data->flags & TEST_CANCEL)
{
g_assert_error (error, G_IO_ERROR, G_IO_ERROR_CANCELLED);
g_main_loop_quit (data->main_loop);
return;
}
g_assert_no_error (error);
g_assert_cmpint (bytes_spliced, ==, strlen (data->data));
if (data->flags & TEST_THREADED_OSTREAM)
{
gsize length = 0;
g_file_get_contents (data->output_path, &received_data,
&length, &error);
g_assert_no_error (error);
g_assert_cmpstr (received_data, ==, data->data);
g_free (received_data);
}
else
{
received_data = g_memory_output_stream_get_data (G_MEMORY_OUTPUT_STREAM (data->ostream));
g_assert_cmpstr (received_data, ==, data->data);
}
g_assert (g_input_stream_is_closed (data->istream));
g_assert (g_output_stream_is_closed (data->ostream));
if (data->flags & TEST_THREADED_ISTREAM)
{
g_unlink (data->input_path);
g_free (data->input_path);
}
if (data->flags & TEST_THREADED_OSTREAM)
{
g_unlink (data->output_path);
g_free (data->output_path);
}
g_main_loop_quit (data->main_loop);
}
static void
test_copy_chunks_start (TestThreadedFlags flags)
{
TestCopyChunksData data;
GError *error = NULL;
GCancellable *cancellable = NULL;
data.main_loop = g_main_loop_new (NULL, FALSE);
data.data = "abcdefghijklmnopqrstuvwxyz";
data.flags = flags;
if (data.flags & TEST_CANCEL)
{
cancellable = g_cancellable_new ();
g_cancellable_cancel (cancellable);
}
if (data.flags & TEST_THREADED_ISTREAM)
{
GFile *file;
GFileIOStream *stream;
file = g_file_new_tmp ("test-inputXXXXXX", &stream, &error);
g_assert_no_error (error);
g_object_unref (stream);
data.input_path = g_file_get_path (file);
g_file_set_contents (data.input_path,
data.data, strlen (data.data),
&error);
g_assert_no_error (error);
data.istream = G_INPUT_STREAM (g_file_read (file, NULL, &error));
g_assert_no_error (error);
g_object_unref (file);
}
else
{
data.istream = g_memory_input_stream_new_from_data (data.data, -1, NULL);
}
if (data.flags & TEST_THREADED_OSTREAM)
{
GFile *file;
GFileIOStream *stream;
file = g_file_new_tmp ("test-outputXXXXXX", &stream, &error);
g_assert_no_error (error);
g_object_unref (stream);
data.output_path = g_file_get_path (file);
data.ostream = G_OUTPUT_STREAM (g_file_replace (file, NULL, FALSE,
G_FILE_CREATE_NONE,
NULL, &error));
g_assert_no_error (error);
g_object_unref (file);
}
else
{
data.ostream = g_memory_output_stream_new (NULL, 0, g_realloc, g_free);
}
g_output_stream_splice_async (data.ostream, data.istream,
G_OUTPUT_STREAM_SPLICE_CLOSE_SOURCE |
G_OUTPUT_STREAM_SPLICE_CLOSE_TARGET,
G_PRIORITY_DEFAULT, cancellable,
test_copy_chunks_splice_cb, &data);
/* We do not hold a ref in data struct, this is to make sure the operation
* keeps the iostream objects alive until it finishes
*/
g_object_unref (data.istream);
g_object_unref (data.ostream);
g_clear_object (&cancellable);
g_main_loop_run (data.main_loop);
g_main_loop_unref (data.main_loop);
}
static void
test_copy_chunks (void)
{
test_copy_chunks_start (TEST_THREADED_NONE);
}
static void
test_copy_chunks_threaded_input (void)
{
test_copy_chunks_start (TEST_THREADED_ISTREAM);
}
static void
test_copy_chunks_threaded_output (void)
{
test_copy_chunks_start (TEST_THREADED_OSTREAM);
}
static void
test_copy_chunks_threaded (void)
{
test_copy_chunks_start (TEST_THREADED_BOTH);
}
static void
test_cancelled (void)
{
test_copy_chunks_start (TEST_THREADED_NONE | TEST_CANCEL);
}
int
main (int argc,
char *argv[])
{
g_test_init (&argc, &argv, NULL);
g_test_add_func ("/async-splice/copy-chunks", test_copy_chunks);
g_test_add_func ("/async-splice/copy-chunks-threaded-input",
test_copy_chunks_threaded_input);
g_test_add_func ("/async-splice/copy-chunks-threaded-output",
test_copy_chunks_threaded_output);
g_test_add_func ("/async-splice/copy-chunks-threaded",
test_copy_chunks_threaded);
g_test_add_func ("/async-splice/cancelled",
test_cancelled);
return g_test_run();
}