[Spice-devel] [spice-gtk v5 20/23] tests: file-transfer include simple tests

Victor Toso lists at victortoso.com
Thu Jul 7 13:39:24 UTC 2016


Hi,

On Wed, Jul 06, 2016 at 11:18:46AM -0500, Jonathon Jongsma wrote:
> On Tue, 2016-07-05 at 15:07 +0200, Victor Toso wrote:
> > This only includes a simple test for file-transfer with a small
> > summary of the possible situations of the test.
> > 
> > As the test is specifically for SpiceFileTransferTask, we don't create
> > a SpiceMainChannel.
> > ---
> >  tests/Makefile.am     |   2 +
> >  tests/file-transfer.c | 190
> > ++++++++++++++++++++++++++++++++++++++++++++++++++
> >  2 files changed, 192 insertions(+)
> >  create mode 100644 tests/file-transfer.c
> > 
> > diff --git a/tests/Makefile.am b/tests/Makefile.am
> > index 1a8b768..6d9cfeb 100644
> > --- a/tests/Makefile.am
> > +++ b/tests/Makefile.am
> > @@ -5,6 +5,7 @@ TESTS = coroutine				\
> >  	util					\
> >  	session					\
> >  	test-spice-uri				\
> > +	test-file-transfer			\
> >  	$(NULL)
> >  
> >  if WITH_PHODAV
> > @@ -38,6 +39,7 @@ coroutine_SOURCES = coroutine.c
> >  session_SOURCES = session.c
> >  pipe_SOURCES = pipe.c
> >  test_spice_uri_SOURCES = uri.c
> > +test_file_transfer_SOURCES = file-transfer.c
> >  usb_acl_helper_SOURCES = usb-acl-helper.c
> >  usb_acl_helper_CFLAGS = -DTESTDIR=\"$(abs_builddir)\"
> >  mock_acl_helper_SOURCES = mock-acl-helper.c
> > diff --git a/tests/file-transfer.c b/tests/file-transfer.c
> > new file mode 100644
> > index 0000000..e59069e
> > --- /dev/null
> > +++ b/tests/file-transfer.c
> > @@ -0,0 +1,190 @@
> > +#include <gio/gio.h>
> > +
> > +#include "spice-file-transfer-task-priv.h"
> > +
> > +typedef struct _Fixture {
> > +    GFile         **files;
> > +    guint           num_files;
> > +    guint           num_files_done;
> > +    GCancellable   *cancellable;
> > +    GMainLoop      *loop;
> > +    GHashTable     *xfer_tasks;
> > +} Fixture;
> > +
> > +typedef struct _AgentAsync {
> > +    SpiceFileTransferTask          *xfer_task;
> > +    VDAgentFileXferStatusMessage    msg;
> > +} AgentAsync;
> > +
> > +#define SINGLE_FILE     1
> > +#define MULTIPLE_FILES  10
> > +
> > +#define T10ns (G_TIME_SPAN_MILLISECOND / 100)
> > +
> > +const gchar content[] = "0123456789_spice-file-transfer-task";
> > +
> > +static void
> > +f_setup(Fixture *f, gconstpointer user_data)
> > +{
> > +    gint i;
> > +    GError *err = NULL;
> > +
> > +    f->loop = g_main_loop_new(NULL, FALSE);
> > +    f->num_files = GPOINTER_TO_UINT(user_data);
> > +    f->num_files_done = 0;
> > +    f->files = g_new0(GFile *, f->num_files + 1);
> > +    f->cancellable = g_cancellable_new();
> > +    for (i = 0; i < f->num_files; i++) {
> > +        gboolean success;
> > +        GFileIOStream *iostream;
> > +
> > +        f->files[i] = g_file_new_tmp("spice-file-transfer-XXXXXX", &iostream,
> > &err);
> > +        g_assert_no_error(err);
> > +        g_assert_nonnull(iostream);
> > +        g_clear_object(&iostream);
> > +
> > +        success = g_file_replace_contents (f->files[i], content,
> > strlen(content), NULL, FALSE,
> > +                                           G_FILE_CREATE_NONE, NULL, f-
> > >cancellable, &err);
> > +        g_assert_no_error(err);
> > +        g_assert_true(success);
> > +    }
> > +}
> > +
> > +static void
> > +f_teardown(Fixture *f, gconstpointer user_data)
> > +{
> > +    gint i;
> > +    GError *err = NULL;
> > +
> > +    g_main_loop_unref(f->loop);
> > +    g_clear_object(&f->cancellable);
> > +    g_clear_pointer(&f->xfer_tasks, g_hash_table_unref);
> > +
> > +    for (i = 0; i < f->num_files; i++) {
> > +        g_file_delete(f->files[i], NULL, &err);
> > +        g_assert_no_error(err);
> > +        g_object_unref(f->files[i]);
> > +    }
> > +    g_clear_pointer(&f->files, g_free);
> > +}
> > +
> > +/****************************************************************************
> > ***
> > + * TEST SIMPLE TRANSFER
> > +
> > ******************************************************************************
> > /
> > +static void
> > +transfer_xfer_task_on_finished(SpiceFileTransferTask *xfer_task,
> > +                               GError *error,
> > +                               gpointer user_data)
> > +{
> > +    Fixture *f = user_data;
> > +
> > +    f->num_files_done++;
> > +    if (f->num_files == f->num_files_done)
> > +        g_main_loop_quit(f->loop);
> > +}
> > +
> > +static void
> > +transfer_read_async_cb(GObject *source_object,
> > +                       GAsyncResult *res,
> > +                       gpointer user_data)
> > +{
> > +    SpiceFileTransferTask *xfer_task;
> > +    gssize count;
> > +    char *buffer;
> > +    GError *error = NULL;
> > +
> > +    xfer_task = SPICE_FILE_TRANSFER_TASK(source_object);
> > +    count = spice_file_transfer_task_read_finish(xfer_task, res, &buffer,
> > &error);
> > +    g_assert_no_error(error);
> > +
> > +    if (count == 0) {
> > +        spice_file_transfer_task_completed(xfer_task, NULL);
> > +        return;
> > +    }
> > +
> > +    spice_file_transfer_task_read_async(xfer_task, transfer_read_async_cb,
> > NULL);
> > +}
> > +
> > +static void
> > +transfer_init_async_cb(GObject *obj, GAsyncResult *res, gpointer data)
> > +{
> > +    GFileInfo *info;
> > +    SpiceFileTransferTask *xfer_task;
> > +    GError *error = NULL;
> > +
> > +    xfer_task = SPICE_FILE_TRANSFER_TASK(obj);
> > +    info = spice_file_transfer_task_init_task_finish(xfer_task, res, &error);
> > +    g_assert_no_error(error);
> > +    g_assert_nonnull(info);
> > +
> > +    /* read file loop */
> > +    spice_file_transfer_task_read_async(xfer_task, transfer_read_async_cb,
> > NULL);
> > +}
> > +
> > +static void
> > +test_simple_transfer(Fixture *f, gconstpointer user_data)
> > +{
> > +    GHashTableIter iter;
> > +    gpointer key, value;
> > +
> > +    f->xfer_tasks = spice_file_transfer_task_create_tasks(f->files, NULL,
> > G_FILE_COPY_NONE, f->cancellable);
> > +    g_hash_table_iter_init(&iter, f->xfer_tasks);
> > +    while (g_hash_table_iter_next(&iter, &key, &value)) {
> > +        SpiceFileTransferTask *xfer_task = SPICE_FILE_TRANSFER_TASK(value);
> > +        g_signal_connect(xfer_task, "finished",
> > G_CALLBACK(transfer_xfer_task_on_finished), f);
> > +        spice_file_transfer_task_init_task_async(xfer_task,
> > transfer_init_async_cb, NULL);
> > +    }
> > +    g_main_loop_run (f->loop);
> > +}
> > +
> > +/* Tests summary:
> > + *
> > + * This tests are specific to SpiceFileTransferTask in order to verify:
> > + * - Cancelation from User;
> > + * - Error/Cancelation from Agent;
> > + * - Bad behavior from Agent;
> > + *
> > + * SpiceFileTransferTask is in charge of initializing, reading and finalizing
> > + * all IO for the file user wants to transfer but being unaware of how the
> > + * protocol works. As there are several combinations of events, these tests
> > + * intend to find errors, leaks and crashes on SpiceFileTransferTask in
> > common
> > + * set of events in order to avoid regression in the drag-and-drop feature.
> > + *
> > + * Small overview of how File Transfer works.
> > + *
> > + * 1.) User calls spice_main_file_copy_async with a list of files to send to
> > the
> > + *     guest
> > + * 2.) SpiceMainChannel creates a SpiceFileTransferTask per File and request
> > its
> > + *     initialization using spice_file_transfer_task_init_task_async(). The
> > init
> > + *     function will open a GFileInpustStream and request the GFileInfo of
> > file;
> 
> typo: Inpust -> Input
> 
> > + * 3.) Using the GFileInfo object, SpiceMainChannel starts the File Transfer
> > + *     protocol with VD_AGENT_FILE_XFER_START. Agent responds with
> > + *     VD_AGENT_FILE_XFER_STATUS_CAN_SEND_DATA which starts the read IO using
> > + *     spice_file_transfer_task_read_async()
> > + * 4.) After the read is done, SpiceMainChannel does an async flush to the
> > + *     agent, using the buffer provided by SpiceFileTransferTask; The read IO
> > + *     will be kept going while SpiceMainChannel has agent tokens to use.
> > + * 5-) After SpiceMainChannel sends enough data, it can always receive:
> > + *     - VD_AGENT_FILE_XFER_STATUS_CAN_SEND_DATA: to send more data;
> > + *     - VD_AGENT_FILE_XFER_STATUS_SUCCESS: all data was sent;
> > + *     - VD_AGENT_FILE_XFER_STATUS_ERROR: unexpected behavior on agent side;
> > + *     - VD_AGENT_FILE_XFER_STATUS_CANCELLED: transfer was cancelled by
> > agent;
> > + * 6-) In any case of termination, the following SpiceFileTransferTask
> > function
> > + *     should always be called: spice_file_transfer_task_completed(); This
> > will
> > + *     trigger from SpiceFileTransferTask all necessary events to finalize
> > user
> > + *     side, memory allocation and so on.
> > + */
> > +int main(int argc, char* argv[])
> > +{
> > +    g_test_init(&argc, &argv, NULL);
> > +
> > +    g_test_add("/spice-file-transfer-task/single/simple-transfer",
> > +               Fixture, GUINT_TO_POINTER(SINGLE_FILE),
> > +               f_setup, test_simple_transfer, f_teardown);
> > +
> > +    g_test_add("/spice-file-transfer-task/multiple/simple-transfer",
> > +               Fixture, GUINT_TO_POINTER(MULTIPLE_FILES),
> > +               f_setup, test_simple_transfer, f_teardown);
> > +
> > +    return g_test_run();
> > +}
> 
> 
> minor typo above

Fixed, thanks!

> 
> Acked-by: Jonathon Jongsma <jjongsma at redhat.com>
> _______________________________________________
> Spice-devel mailing list
> Spice-devel at lists.freedesktop.org
> https://lists.freedesktop.org/mailman/listinfo/spice-devel


More information about the Spice-devel mailing list