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@xxxxxxxxxx> > _______________________________________________ > Spice-devel mailing list > Spice-devel@xxxxxxxxxxxxxxxxxxxxx > https://lists.freedesktop.org/mailman/listinfo/spice-devel _______________________________________________ Spice-devel mailing list Spice-devel@xxxxxxxxxxxxxxxxxxxxx https://lists.freedesktop.org/mailman/listinfo/spice-devel