[libgdata] Bug 624141 — Add batch operation support to Documents service
- From: Philip Withnall <pwithnall src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [libgdata] Bug 624141 — Add batch operation support to Documents service
- Date: Thu, 26 Aug 2010 23:03:54 +0000 (UTC)
commit 4fe7a305eb88a4d38a969f0c00485996802fdcf1
Author: Philip Withnall <philip tecnocode co uk>
Date: Fri Aug 27 00:02:34 2010 +0100
Bug 624141 â?? Add batch operation support to Documents service
Add the GDataBatchable interface to GDataDocumentsService and add the relevant
test cases to the documents test suite. Closes: bgo#624141
gdata/services/documents/gdata-documents-service.c | 3 +-
gdata/tests/common.c | 6 +-
gdata/tests/documents.c | 250 ++++++++++++++++++++
3 files changed, 257 insertions(+), 2 deletions(-)
---
diff --git a/gdata/services/documents/gdata-documents-service.c b/gdata/services/documents/gdata-documents-service.c
index 70fa8f7..27e6549 100644
--- a/gdata/services/documents/gdata-documents-service.c
+++ b/gdata/services/documents/gdata-documents-service.c
@@ -47,6 +47,7 @@
#include "gdata-documents-spreadsheet.h"
#include "gdata-documents-text.h"
#include "gdata-documents-presentation.h"
+#include "gdata-batchable.h"
#include "gdata-service.h"
#include "gdata-private.h"
#include "gdata-upload-stream.h"
@@ -72,7 +73,7 @@ enum {
PROP_SPREADSHEET_SERVICE = 1
};
-G_DEFINE_TYPE (GDataDocumentsService, gdata_documents_service, GDATA_TYPE_SERVICE)
+G_DEFINE_TYPE_WITH_CODE (GDataDocumentsService, gdata_documents_service, GDATA_TYPE_SERVICE, G_IMPLEMENT_INTERFACE (GDATA_TYPE_BATCHABLE, NULL))
static void
gdata_documents_service_class_init (GDataDocumentsServiceClass *klass)
diff --git a/gdata/tests/common.c b/gdata/tests/common.c
index 9b7411c..37d3e7d 100644
--- a/gdata/tests/common.c
+++ b/gdata/tests/common.c
@@ -202,9 +202,13 @@ test_batch_operation_insertion_update_cb (guint operation_id, GDataBatchOperatio
g_assert_cmpstr (gdata_entry_get_title (entry), ==, gdata_entry_get_title (data->entry));
g_assert_cmpstr (gdata_entry_get_summary (entry), ==, gdata_entry_get_summary (data->entry));
g_assert_cmpstr (gdata_entry_get_content (entry), ==, gdata_entry_get_content (data->entry));
- g_assert_cmpstr (gdata_entry_get_content_uri (entry), ==, gdata_entry_get_content_uri (data->entry));
g_assert_cmpstr (gdata_entry_get_rights (entry), ==, gdata_entry_get_rights (data->entry));
+ /* Only test for differences in content URI if we had one to begin with, since the inserted entry could feasibly generate and return
+ * new content. */
+ if (gdata_entry_get_content_uri (data->entry) != NULL)
+ g_assert_cmpstr (gdata_entry_get_content_uri (entry), ==, gdata_entry_get_content_uri (data->entry));
+
/* Copy the inserted entry for the calling test code to prod later */
if (data->returned_entry != NULL)
*(data->returned_entry) = g_object_ref (entry);
diff --git a/gdata/tests/documents.c b/gdata/tests/documents.c
index 6a1dbf2..79fec19 100644
--- a/gdata/tests/documents.c
+++ b/gdata/tests/documents.c
@@ -580,6 +580,251 @@ test_query_etag (void)
g_object_unref (query);
}
+static void
+test_batch (gconstpointer service)
+{
+ GDataBatchOperation *operation;
+ GDataService *service2;
+ GDataDocumentsText *doc, *doc2, *doc3;
+ GDataEntry *inserted_entry, *inserted_entry_updated, *inserted_entry2, *inserted_entry2_updated, *inserted_entry3;
+ gchar *feed_uri;
+ guint op_id, op_id2, op_id3;
+ GError *error = NULL, *entry_error = NULL;
+
+ /* Here we hardcode the feed URI, but it should really be extracted from a document feed, as the GDATA_LINK_BATCH link */
+ operation = gdata_batchable_create_operation (GDATA_BATCHABLE (service), "https://docs.google.com/feeds/documents/private/full/batch");
+
+ /* Check the properties of the operation */
+ g_assert (gdata_batch_operation_get_service (operation) == service);
+ g_assert_cmpstr (gdata_batch_operation_get_feed_uri (operation), ==, "https://docs.google.com/feeds/documents/private/full/batch");
+
+ g_object_get (operation,
+ "service", &service2,
+ "feed-uri", &feed_uri,
+ NULL);
+
+ g_assert (service2 == service);
+ g_assert_cmpstr (feed_uri, ==, "https://docs.google.com/feeds/documents/private/full/batch");
+
+ g_object_unref (service2);
+ g_free (feed_uri);
+
+ /* Run a singleton batch operation to insert a new entry */
+ doc = gdata_documents_text_new (NULL);
+ gdata_entry_set_title (GDATA_ENTRY (doc), "My First Document");
+
+ gdata_test_batch_operation_insertion (operation, GDATA_ENTRY (doc), &inserted_entry, NULL);
+ g_assert (gdata_batch_operation_run (operation, NULL, &error) == TRUE);
+ g_assert_no_error (error);
+
+ g_clear_error (&error);
+ g_object_unref (operation);
+ g_object_unref (doc);
+
+ /* Run another batch operation to insert another entry and query the previous one */
+ doc2 = gdata_documents_text_new (NULL);
+ gdata_entry_set_title (GDATA_ENTRY (doc2), "I'm a poet and I didn't know it");
+
+ operation = gdata_batchable_create_operation (GDATA_BATCHABLE (service), "https://docs.google.com/feeds/documents/private/full/batch");
+ op_id = gdata_test_batch_operation_insertion (operation, GDATA_ENTRY (doc2), &inserted_entry2, NULL);
+ op_id2 = gdata_test_batch_operation_query (operation, gdata_entry_get_id (inserted_entry), GDATA_TYPE_DOCUMENTS_TEXT, inserted_entry, NULL,
+ NULL);
+ g_assert_cmpuint (op_id, !=, op_id2);
+
+ g_assert (gdata_batch_operation_run (operation, NULL, &error) == TRUE);
+ g_assert_no_error (error);
+
+ g_clear_error (&error);
+ g_object_unref (operation);
+ g_object_unref (doc2);
+
+ /* Run another batch operation to query one of the entries we just created, since it seems that the ETags for documents change for no
+ * apparent reason when you're not looking. */
+ operation = gdata_batchable_create_operation (GDATA_BATCHABLE (service), "https://docs.google.com/feeds/documents/private/full/batch");
+ gdata_test_batch_operation_query (operation, gdata_entry_get_id (inserted_entry), GDATA_TYPE_DOCUMENTS_TEXT, inserted_entry,
+ &inserted_entry_updated, NULL);
+
+ g_assert (gdata_batch_operation_run (operation, NULL, &error) == TRUE);
+ g_assert_no_error (error);
+
+ g_clear_error (&error);
+ g_object_unref (operation);
+ g_object_unref (inserted_entry);
+
+ /* Run another batch operation to query the other entry we just created. It would be sensible to batch this query together with the previous
+ * one, seeing as we're testing _batch_ functionality. Funnily enough, the combination of two idempotent operations changes the ETags and
+ * makes the whole effort worthless. */
+ operation = gdata_batchable_create_operation (GDATA_BATCHABLE (service), "https://docs.google.com/feeds/documents/private/full/batch");
+ gdata_test_batch_operation_query (operation, gdata_entry_get_id (inserted_entry2), GDATA_TYPE_DOCUMENTS_TEXT, inserted_entry2,
+ &inserted_entry2_updated, NULL);
+
+ g_assert (gdata_batch_operation_run (operation, NULL, &error) == TRUE);
+ g_assert_no_error (error);
+
+ g_clear_error (&error);
+ g_object_unref (operation);
+
+ /* Run another batch operation to delete the first entry and a fictitious one to test error handling, and update the second entry */
+ gdata_entry_set_title (inserted_entry2_updated, "War & Peace");
+ doc3 = gdata_documents_text_new ("foobar");
+
+ operation = gdata_batchable_create_operation (GDATA_BATCHABLE (service), "https://docs.google.com/feeds/documents/private/full/batch");
+ op_id = gdata_test_batch_operation_deletion (operation, inserted_entry_updated, NULL);
+ op_id2 = gdata_test_batch_operation_deletion (operation, GDATA_ENTRY (doc3), &entry_error);
+ op_id3 = gdata_test_batch_operation_update (operation, inserted_entry2_updated, &inserted_entry3, NULL);
+ g_assert_cmpuint (op_id, !=, op_id2);
+ g_assert_cmpuint (op_id, !=, op_id3);
+ g_assert_cmpuint (op_id2, !=, op_id3);
+
+ g_assert (gdata_batch_operation_run (operation, NULL, &error) == TRUE);
+ g_assert_no_error (error);
+
+ g_assert_error (entry_error, GDATA_SERVICE_ERROR, GDATA_SERVICE_ERROR_PROTOCOL_ERROR);
+
+ g_clear_error (&error);
+ g_clear_error (&entry_error);
+ g_object_unref (operation);
+ g_object_unref (inserted_entry_updated);
+ g_object_unref (inserted_entry2_updated);
+ g_object_unref (doc3);
+
+ /* Run another batch operation to update the second entry with the wrong ETag (i.e. pass the old version of the entry to the batch operation
+ * to test error handling */
+ operation = gdata_batchable_create_operation (GDATA_BATCHABLE (service), "https://docs.google.com/feeds/documents/private/full/batch");
+ gdata_test_batch_operation_update (operation, inserted_entry2, NULL, &entry_error);
+ g_assert (gdata_batch_operation_run (operation, NULL, &error) == TRUE);
+ g_assert_no_error (error);
+
+ g_assert_error (entry_error, GDATA_SERVICE_ERROR, GDATA_SERVICE_ERROR_CONFLICT);
+
+ g_clear_error (&error);
+ g_clear_error (&entry_error);
+ g_object_unref (operation);
+ g_object_unref (inserted_entry2);
+
+ /* Run a final batch operation to delete the second entry */
+ operation = gdata_batchable_create_operation (GDATA_BATCHABLE (service), "https://docs.google.com/feeds/documents/private/full/batch");
+ gdata_test_batch_operation_deletion (operation, inserted_entry3, NULL);
+ g_assert (gdata_batch_operation_run (operation, NULL, &error) == TRUE);
+ g_assert_no_error (error);
+
+ g_clear_error (&error);
+ g_object_unref (operation);
+ g_object_unref (inserted_entry3);
+}
+
+typedef struct {
+ GDataDocumentsEntry *new_doc;
+} BatchAsyncData;
+
+static void
+setup_batch_async (BatchAsyncData *data, gconstpointer service)
+{
+ GDataDocumentsText *doc;
+ GError *error = NULL;
+
+ /* Insert a new document which we can query asyncly */
+ doc = gdata_documents_text_new (NULL);
+ gdata_entry_set_title (GDATA_ENTRY (doc), "A View from the Bridge");
+
+ data->new_doc = gdata_documents_service_upload_document (GDATA_DOCUMENTS_SERVICE (service), GDATA_DOCUMENTS_ENTRY (doc), NULL, NULL, NULL,
+ &error);
+ g_assert_no_error (error);
+ g_assert (GDATA_IS_DOCUMENTS_TEXT (data->new_doc));
+ g_clear_error (&error);
+
+ g_object_unref (doc);
+}
+
+static void
+test_batch_async_cb (GDataBatchOperation *operation, GAsyncResult *async_result, GMainLoop *main_loop)
+{
+ GError *error = NULL;
+
+ g_assert (gdata_batch_operation_run_finish (operation, async_result, &error) == TRUE);
+ g_assert_no_error (error);
+ g_clear_error (&error);
+
+ g_main_loop_quit (main_loop);
+}
+
+static void
+test_batch_async (BatchAsyncData *data, gconstpointer service)
+{
+ GDataBatchOperation *operation;
+ guint op_id;
+ GMainLoop *main_loop;
+
+ /* Run an async query operation on the document */
+ operation = gdata_batchable_create_operation (GDATA_BATCHABLE (service), "https://docs.google.com/feeds/documents/private/full/batch");
+ op_id = gdata_test_batch_operation_query (operation, gdata_entry_get_id (GDATA_ENTRY (data->new_doc)), GDATA_TYPE_DOCUMENTS_TEXT,
+ GDATA_ENTRY (data->new_doc), NULL, NULL);
+
+ main_loop = g_main_loop_new (NULL, TRUE);
+
+ gdata_batch_operation_run_async (operation, NULL, (GAsyncReadyCallback) test_batch_async_cb, main_loop);
+
+ g_main_loop_run (main_loop);
+ g_main_loop_unref (main_loop);
+}
+
+static void
+test_batch_async_cancellation_cb (GDataBatchOperation *operation, GAsyncResult *async_result, GMainLoop *main_loop)
+{
+ GError *error = NULL;
+
+ g_assert (gdata_batch_operation_run_finish (operation, async_result, &error) == FALSE);
+ g_assert_error (error, G_IO_ERROR, G_IO_ERROR_CANCELLED);
+ g_clear_error (&error);
+
+ g_main_loop_quit (main_loop);
+}
+
+static void
+test_batch_async_cancellation (BatchAsyncData *data, gconstpointer service)
+{
+ GDataBatchOperation *operation;
+ guint op_id;
+ GMainLoop *main_loop;
+ GCancellable *cancellable;
+
+ /* Run an async query operation on the document */
+ operation = gdata_batchable_create_operation (GDATA_BATCHABLE (service), "https://docs.google.com/feeds/documents/private/full/batch");
+ op_id = gdata_test_batch_operation_query (operation, gdata_entry_get_id (GDATA_ENTRY (data->new_doc)), GDATA_TYPE_DOCUMENTS_TEXT,
+ GDATA_ENTRY (data->new_doc), NULL, NULL);
+
+ main_loop = g_main_loop_new (NULL, TRUE);
+ cancellable = g_cancellable_new ();
+
+ gdata_batch_operation_run_async (operation, cancellable, (GAsyncReadyCallback) test_batch_async_cancellation_cb, main_loop);
+ g_cancellable_cancel (cancellable); /* this should cancel the operation before it even starts, as we haven't run the main loop yet */
+
+ g_main_loop_run (main_loop);
+ g_main_loop_unref (main_loop);
+ g_object_unref (cancellable);
+}
+
+static void
+teardown_batch_async (BatchAsyncData *data, gconstpointer service)
+{
+ GDataEntry *document;
+ GError *error = NULL;
+
+ /* Re-query the document in case its ETag has changed */
+ document = gdata_service_query_single_entry (GDATA_SERVICE (service), gdata_entry_get_id (GDATA_ENTRY (data->new_doc)), NULL,
+ GDATA_TYPE_DOCUMENTS_TEXT, NULL, &error);
+ g_assert_no_error (error);
+ g_clear_error (&error);
+
+ /* Delete the document */
+ g_assert (gdata_service_delete_entry (GDATA_SERVICE (service), document, NULL, &error) == TRUE);
+ g_assert_no_error (error);
+ g_clear_error (&error);
+
+ g_object_unref (data->new_doc);
+ g_object_unref (document);
+}
+
int
main (int argc, char *argv[])
{
@@ -616,6 +861,11 @@ main (int argc, char *argv[])
g_test_add_data_func ("/documents/move/move_to_folder", service, test_add_file_folder_and_move);
g_test_add_data_func ("/documents/move/remove_from_folder", service, test_add_remove_file_from_folder);
/*g_test_add_data_func ("/documents/remove/all", service, test_remove_all_documents_and_folders);*/
+
+ g_test_add_data_func ("/documents/batch", service, test_batch);
+ g_test_add ("/documents/batch/async", BatchAsyncData, service, setup_batch_async, test_batch_async, teardown_batch_async);
+ g_test_add ("/documents/batch/async/cancellation", BatchAsyncData, service, setup_batch_async, test_batch_async_cancellation,
+ teardown_batch_async);
}
g_test_add_func ("/documents/query/etag", test_query_etag);
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]