[libgnome-keyring] Add more tests of cancellation, test tweaks



commit f40819ccd588856a6b87b509a9e83b1c1fa19928
Author: Stef Walter <stefw gnome org>
Date:   Tue Jan 31 13:48:36 2012 +0100

    Add more tests of cancellation, test tweaks
    
     * Add some tests of cancellation
     * Update the egg-testing.[ch] files, for running tests within
       a mainloop

 .gitignore                           |    2 +
 egg/egg-testing.c                    |  161 +++++++++++++++++++++++++--
 egg/egg-testing.h                    |   23 ++++
 library/tests/Makefile.am            |    1 +
 library/tests/mock-service-cancel.py |   16 +++
 library/tests/mock/service.py        |   12 +-
 library/tests/test-cancel.c          |  203 ++++++++++++++++++++++++++++++++++
 library/tests/test-keyrings.c        |   47 ++------
 8 files changed, 414 insertions(+), 51 deletions(-)
---
diff --git a/.gitignore b/.gitignore
index 719576e..618d46d 100644
--- a/.gitignore
+++ b/.gitignore
@@ -15,6 +15,7 @@ run-auto-test.h
 *.tmp
 *.prj
 *.pws
+*.pyc
 *.anjuta
 *.tar.gz
 .*project
@@ -119,6 +120,7 @@ run-auto-test.h
 /library/tests/frob-default-keyring
 /library/tests/frob-unlock-keyring
 /library/tests/test-any-daemon
+/library/tests/test-cancel
 /library/tests/test-prompting
 /library/tests/test-keyrings
 /library/tests/test-memory
diff --git a/egg/egg-testing.c b/egg/egg-testing.c
index 458b71f..3b9a423 100644
--- a/egg/egg-testing.c
+++ b/egg/egg-testing.c
@@ -25,30 +25,83 @@
 
 #include "egg-testing.h"
 
+#include <glib-object.h>
+
+#include <valgrind/valgrind.h>
+
+#include <glib.h>
+#include <glib/gstdio.h>
+
+#include <errno.h>
+#include <fcntl.h>
+#include <unistd.h>
+
 static const char HEXC[] = "0123456789ABCDEF";
 
-static gchar*
-hex_dump (const guchar *data, gsize n_data)
+gchar *
+egg_test_escape_data (const guchar *data,
+                      gsize n_data)
 {
 	GString *result;
+	gchar c;
 	gsize i;
 	guchar j;
 
-	g_assert (data);
+	g_assert (data != NULL);
 
 	result = g_string_sized_new (n_data * 2 + 1);
 	for (i = 0; i < n_data; ++i) {
-		g_string_append (result, "\\x");
-
-		j = data[i] >> 4 & 0xf;
-		g_string_append_c (result, HEXC[j]);
-		j = data[i] & 0xf;
-		g_string_append_c (result, HEXC[j]);
+		c = data[i];
+		if (g_ascii_isprint (c) && !strchr ("\n\r\v", c)) {
+			g_string_append_c (result, c);
+		} else {
+			g_string_append (result, "\\x");
+			j = c >> 4 & 0xf;
+			g_string_append_c (result, HEXC[j]);
+			j = c & 0xf;
+			g_string_append_c (result, HEXC[j]);
+		}
 	}
 
 	return g_string_free (result, FALSE);
 }
 
+static gboolean
+is_readable_ptr (gpointer was_object)
+{
+	static gint test_memory_fd = -1;
+
+	/* First make sure this memory is still accessible */
+	if (test_memory_fd < 0)
+		test_memory_fd = g_open ("/dev/null", O_WRONLY, 0);
+	if (write (test_memory_fd, was_object, 1) > 0)
+		return TRUE;
+	return (errno != EFAULT);
+}
+
+void
+egg_assertion_not_object (const char *domain,
+                          const char *file,
+                          int         line,
+                          const char *func,
+                          const char *expr,
+                          gpointer was_object)
+{
+	gchar *s;
+
+	if (RUNNING_ON_VALGRIND)
+		return;
+
+	if (!is_readable_ptr (was_object))
+		return;
+
+	if (G_IS_OBJECT (was_object)) {
+		s = g_strdup_printf ("assertion failed: %s is still referenced", expr);
+		g_assertion_message (domain, file, line, func, s);
+		g_free (s);
+	}
+}
+
 void
 egg_assertion_message_cmpmem (const char     *domain,
                               const char     *file,
@@ -62,11 +115,97 @@ egg_assertion_message_cmpmem (const char     *domain,
                               gsize           n_arg2)
 {
   char *a1, *a2, *s;
-  a1 = arg1 ? hex_dump (arg1, n_arg1) : g_strdup ("NULL");
-  a2 = arg2 ? hex_dump (arg2, n_arg2) : g_strdup ("NULL");
+  a1 = arg1 ? egg_test_escape_data (arg1, n_arg1) : g_strdup ("NULL");
+  a2 = arg2 ? egg_test_escape_data (arg2, n_arg2) : g_strdup ("NULL");
   s = g_strdup_printf ("assertion failed (%s): (%s %s %s)", expr, a1, cmp, a2);
   g_free (a1);
   g_free (a2);
   g_assertion_message (domain, file, line, func, s);
   g_free (s);
 }
+
+static void (*wait_stop_impl) (void);
+static gboolean (*wait_until_impl) (int timeout);
+
+void
+egg_test_wait_stop (void)
+{
+	g_assert (wait_stop_impl != NULL);
+	(wait_stop_impl) ();
+}
+
+gboolean
+egg_test_wait_until (int timeout)
+{
+	g_assert (wait_until_impl != NULL);
+	return (wait_until_impl) (timeout);
+}
+
+void
+egg_test_wait_idle (void)
+{
+	GMainContext *context;
+
+	g_assert (wait_until_impl != NULL);
+
+	context = g_main_context_get_thread_default ();
+	while (g_main_context_iteration (context, FALSE));
+}
+
+static GMainLoop *wait_loop = NULL;
+
+static void
+loop_wait_stop (void)
+{
+	g_assert (wait_loop != NULL);
+	g_main_loop_quit (wait_loop);
+}
+
+static gboolean
+on_loop_wait_timeout (gpointer data)
+{
+	gboolean *timed_out = data;
+	*timed_out = TRUE;
+
+	g_assert (wait_loop != NULL);
+	g_main_loop_quit (wait_loop);
+
+	return TRUE; /* we remove this source later */
+}
+
+static gboolean
+loop_wait_until (int timeout)
+{
+	gboolean timed_out = FALSE;
+	guint source;
+
+	g_assert (wait_loop == NULL);
+	wait_loop = g_main_loop_new (g_main_context_get_thread_default (), FALSE);
+
+	source = g_timeout_add (timeout, on_loop_wait_timeout, &timed_out);
+
+	g_main_loop_run (wait_loop);
+
+	g_source_remove (source);
+	g_main_loop_unref (wait_loop);
+	wait_loop = NULL;
+	return !timed_out;
+}
+
+gint
+egg_tests_run_with_loop (void)
+{
+	gint ret;
+
+	wait_stop_impl = loop_wait_stop;
+	wait_until_impl = loop_wait_until;
+
+	ret = g_test_run ();
+
+	wait_stop_impl = NULL;
+	wait_until_impl = NULL;
+
+	while (g_main_context_iteration (NULL, FALSE));
+
+	return ret;
+}
diff --git a/egg/egg-testing.h b/egg/egg-testing.h
index 14bc8e9..d94379d 100644
--- a/egg/egg-testing.h
+++ b/egg/egg-testing.h
@@ -37,10 +37,33 @@
 	            G_STRFUNC, #a "[" #na"] " #cmp " " #b "[" #nb "]", \
                     __p1, __n1, #cmp, __p2, __n2); } while (0)
 
+#define egg_assert_not_object(p) \
+	(egg_assertion_not_object (G_LOG_DOMAIN, __FILE__, __LINE__, G_STRFUNC, #p, (p)))
+
+void       egg_assertion_not_object          (const char *domain,
+                                              const char *file,
+                                              int         line,
+                                              const char *func,
+                                              const char *expr,
+                                              gpointer was_object);
+
 void       egg_assertion_message_cmpmem        (const char *domain, const char *file,
                                                 int line, const char *func,
                                                 const char *expr, gconstpointer arg1,
                                                 gsize n_arg1, const char *cmp,
                                                 gconstpointer arg2, gsize n_arg2);
 
+gchar *    egg_test_escape_data                (const guchar *data,
+                                                gsize size);
+
+void       egg_test_wait_stop                  (void);
+
+#define    egg_test_wait()                     g_assert (egg_test_wait_until (20000) != FALSE)
+
+gboolean   egg_test_wait_until                 (int timeout);
+
+void       egg_test_wait_idle                  (void);
+
+gint       egg_tests_run_with_loop             (void);
+
 #endif /* EGG_DH_H_ */
diff --git a/library/tests/Makefile.am b/library/tests/Makefile.am
index 343eae4..7b67470 100644
--- a/library/tests/Makefile.am
+++ b/library/tests/Makefile.am
@@ -27,6 +27,7 @@ LDADD =  \
 TEST_PROGS = \
 	test-memory \
 	test-keyrings \
+	test-cancel \
 	test-other
 
 check_PROGRAMS = \
diff --git a/library/tests/mock-service-cancel.py b/library/tests/mock-service-cancel.py
new file mode 100644
index 0000000..395b1ef
--- /dev/null
+++ b/library/tests/mock-service-cancel.py
@@ -0,0 +1,16 @@
+#!/usr/bin/env python
+
+import dbus
+import mock
+import time
+
+class SecretService(mock.SecretService):
+
+	@dbus.service.method('org.freedesktop.Secret.Service')
+	def SearchItems(self, attributes):
+		time.sleep(0.02)
+		return mock.SecretService.SearchItems(self, attributes)
+
+service = SecretService()
+service.add_standard_objects()
+service.listen()
\ No newline at end of file
diff --git a/library/tests/mock/service.py b/library/tests/mock/service.py
index 0ea3801..bb9fb82 100644
--- a/library/tests/mock/service.py
+++ b/library/tests/mock/service.py
@@ -488,18 +488,18 @@ class SecretService(dbus.service.Object):
 
 	def add_standard_objects(self):
 		collection = SecretCollection(self, "english", label="Collection One", locked=False)
-		SecretItem(collection, "item_one", label="Item One",
+		SecretItem(collection, "1", label="Item One",
 		           attributes={ "number": "1", "string": "one", "even": "false" },
 		           secret="111", type="org.mock.type.Store")
-		SecretItem(collection, "item_two", attributes={ "number": "2", "string": "two", "even": "true" }, secret="222")
-		SecretItem(collection, "item_three", attributes={ "number": "3", "string": "three", "even": "false" }, secret="3333")
+		SecretItem(collection, "2", attributes={ "number": "2", "string": "two", "even": "true" }, secret="222")
+		SecretItem(collection, "3", attributes={ "number": "3", "string": "three", "even": "false" }, secret="3333")
 
 		self.set_alias('default', collection)
 
 		collection = SecretCollection(self, "spanish", locked=True)
-		SecretItem(collection, "item_one", attributes={ "number": "1", "string": "uno", "even": "false" }, secret="111")
-		SecretItem(collection, "item_two", attributes={ "number": "2", "string": "dos", "even": "true" }, secret="222")
-		SecretItem(collection, "item_three", attributes={ "number": "3", "string": "tres", "even": "false" }, secret="3333")
+		SecretItem(collection, "10", attributes={ "number": "1", "string": "uno", "even": "false" }, secret="111")
+		SecretItem(collection, "20", attributes={ "number": "2", "string": "dos", "even": "true" }, secret="222")
+		SecretItem(collection, "30", attributes={ "number": "3", "string": "tres", "even": "false" }, secret="3333")
 
 		collection = SecretCollection(self, "empty", locked=False)
 		collection = SecretCollection(self, "session", label="Session Keyring", locked=False)
diff --git a/library/tests/test-cancel.c b/library/tests/test-cancel.c
new file mode 100644
index 0000000..70931f7
--- /dev/null
+++ b/library/tests/test-cancel.c
@@ -0,0 +1,203 @@
+/* -*- Mode: C; indent-tabs-mode: t; c-basic-offset: 8; tab-width: 8 -*- */
+/* unit-test-keyrings.c: Test basic keyring functionality
+
+   Copyright (C) 2012 Red Hat Inc.
+
+   The Gnome Keyring Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Library General Public License as
+   published by the Free Software Foundation; either version 2 of the
+   License, or (at your option) any later version.
+
+   The Gnome Keyring Library 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.  See the GNU
+   Library General Public License for more details.
+
+   You should have received a copy of the GNU Library General Public
+   License along with the Gnome Library; see the file COPYING.LIB.  If not,
+   write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+   Boston, MA 02111-1307, USA.
+
+   Author: Stef Walter <stefw gnome org>
+*/
+
+#include "config.h"
+
+#include "gnome-keyring.h"
+#include "gkr-misc.h"
+
+#include "mock-service.h"
+
+#include "egg/egg-testing.h"
+
+static void
+on_items_found (GnomeKeyringResult result,
+                GList *list,
+                gpointer data)
+{
+	GnomeKeyringResult *res = data;
+	g_assert_cmpint (result, ==, *res);
+	egg_test_wait_stop ();
+}
+
+static void
+test_immediate (void)
+{
+	GnomeKeyringAttributeList *attrs;
+	GnomeKeyringResult res = GNOME_KEYRING_RESULT_CANCELLED;
+	gpointer operation;
+
+	attrs = gnome_keyring_attribute_list_new ();
+	gnome_keyring_attribute_list_append_string (attrs, "even", "false");
+
+	operation = gnome_keyring_find_items (GNOME_KEYRING_ITEM_GENERIC_SECRET,
+	                                      attrs, on_items_found, &res, NULL);
+	gnome_keyring_attribute_list_free (attrs);
+
+	gnome_keyring_cancel_request (operation);
+
+	egg_test_wait ();
+}
+
+static void
+test_twice (void)
+{
+	GnomeKeyringAttributeList *attrs;
+	GnomeKeyringResult res = GNOME_KEYRING_RESULT_CANCELLED;
+	gpointer operation;
+
+	attrs = gnome_keyring_attribute_list_new ();
+	gnome_keyring_attribute_list_append_string (attrs, "even", "false");
+
+	operation = gnome_keyring_find_items (GNOME_KEYRING_ITEM_GENERIC_SECRET,
+	                                      attrs, on_items_found, &res, NULL);
+	gnome_keyring_attribute_list_free (attrs);
+
+	gnome_keyring_cancel_request (operation);
+	gnome_keyring_cancel_request (operation);
+
+	egg_test_wait ();
+}
+
+typedef struct {
+	gint which;
+	GnomeKeyringResult expect;
+	gpointer operation;
+	GHashTable *requests;
+} Request;
+
+static void
+request_free (gpointer data)
+{
+	g_slice_free (Request, data);
+}
+
+static void
+on_intense_request (GnomeKeyringResult result,
+                    GList *list,
+                    gpointer data)
+{
+	Request *request = data;
+	g_assert_cmpint (result, ==, request->expect);
+	g_hash_table_remove (request->requests, &request->which);
+
+	if (result == GNOME_KEYRING_RESULT_CANCELLED)
+		g_printerr ("!");
+	else if (result == GNOME_KEYRING_RESULT_OK)
+		g_printerr (".");
+	else
+		g_printerr ("E");
+}
+
+static void
+test_intense (void)
+{
+	#define ITERATIONS 200
+	GnomeKeyringAttributeList *attrs;
+	Request *request;
+	GHashTable *requests;
+	GHashTableIter iter;
+	gint *lookup;
+	gint which;
+	gint i = 0;
+
+	attrs = gnome_keyring_attribute_list_new ();
+	gnome_keyring_attribute_list_append_string (attrs, "even", "false");
+
+	requests = g_hash_table_new_full (g_int_hash, g_int_equal, NULL, NULL);
+
+	for (;;) {
+		if (i++ < ITERATIONS) {
+			request = g_slice_new0 (Request);
+			request->which = i;
+			request->requests = requests;
+			request->expect = GNOME_KEYRING_RESULT_OK;
+			request->operation = gnome_keyring_find_items (GNOME_KEYRING_ITEM_GENERIC_SECRET,
+			                                               attrs, on_intense_request,
+			                                               request, request_free);
+
+			g_hash_table_insert (requests, &request->which, request);
+			which = g_random_int_range (0, MIN (i, ITERATIONS));
+
+		} else {
+			g_hash_table_iter_init (&iter, requests);
+			if (!g_hash_table_iter_next (&iter, (gpointer *)&lookup, NULL))
+				break;
+			which = *lookup;
+		}
+
+		egg_test_wait_until (g_random_int_range (2, 50));
+		g_printerr (" ");
+
+		request = g_hash_table_lookup (requests, &which);
+		if (request != NULL) {
+			request->expect = GNOME_KEYRING_RESULT_CANCELLED;
+			gnome_keyring_cancel_request (request->operation);
+		}
+	}
+
+	g_hash_table_destroy (requests);
+	gnome_keyring_attribute_list_free (attrs);
+}
+
+int
+main (int argc, char **argv)
+{
+	const gchar *address;
+	GError *error = NULL;
+	const gchar *service;
+	int ret = 0;
+
+	g_test_init (&argc, &argv, NULL);
+	g_set_prgname ("test-cancel");
+
+	/* Need to have DBUS running */
+	address = g_getenv ("DBUS_SESSION_BUS_ADDRESS");
+	if (!address || !address[0]) {
+		g_printerr ("no DBus session available, skipping tests.");
+		return 0;
+	}
+
+	service = g_getenv ("GNOME_KEYRING_TEST_SERVICE");
+	if (service && service[0])
+		service = NULL;
+
+	g_test_add_func ("/cancel/immediate", test_immediate);
+	g_test_add_func ("/cancel/twice", test_twice);
+	if (g_test_thorough ())
+		g_test_add_func ("/cancel/intense", test_intense);
+
+	if (service) {
+		g_printerr ("running tests against secret service: %s", service);
+		gkr_service_name = service;
+
+	} else if (!mock_service_start ("mock-service-cancel.py", &error)) {
+		g_printerr ("\nCouldn't start mock secret service: %s\n\n", error->message);
+		return 1;
+	}
+
+	ret = egg_tests_run_with_loop ();
+
+	mock_service_stop ();
+	return ret;
+}
diff --git a/library/tests/test-keyrings.c b/library/tests/test-keyrings.c
index 4a15b2f..13c7fac 100644
--- a/library/tests/test-keyrings.c
+++ b/library/tests/test-keyrings.c
@@ -28,6 +28,8 @@
 
 #include "mock-service.h"
 
+#include "egg/egg-testing.h"
+
 #include <glib.h>
 
 #include <stdlib.h>
@@ -45,27 +47,6 @@ static gchar *default_name = NULL;
 #define DISPLAY_NAME "Item Display Name"
 #define SECRET "item-secret"
 
-static GMainLoop *mainloop = NULL;
-
-static gboolean
-quit_loop (gpointer data)
-{
-	g_main_loop_quit (data);
-	return TRUE;
-}
-
-static void
-mainloop_run (int timeout)
-{
-	guint id = 0;
-
-	if (timeout)
-		id = g_timeout_add (timeout, quit_loop, mainloop);
-	g_main_loop_run (mainloop);
-	if (timeout)
-		g_source_remove (id);
-}
-
 static void
 test_remove_incomplete (void)
 {
@@ -410,7 +391,7 @@ static void
 done_grant_access (GnomeKeyringResult res, gpointer data)
 {
 	grant_access_result = res;
-	g_main_loop_quit (mainloop);
+	egg_test_wait_stop ();
 }
 
 static void
@@ -437,7 +418,7 @@ test_keyring_grant_access (void)
 	/* "callback already called" */
 	g_assert_cmpint (grant_access_result, ==, GNOME_KEYRING_RESULT_CANCELLED);
 
-	mainloop_run (2000);
+	egg_test_wait ();
 
 	g_assert_cmpint (GNOME_KEYRING_RESULT_OK, ==, grant_access_result);
 
@@ -465,7 +446,7 @@ static void
 done_store_password (GnomeKeyringResult res, gpointer data)
 {
 	*((GnomeKeyringResult*)data) = res;
-	g_main_loop_quit (mainloop);
+	egg_test_wait_stop ();
 }
 
 static void
@@ -501,7 +482,7 @@ test_store_password (void)
 	/* "callback already called" */
 	g_assert_cmpint (res, ==, GNOME_KEYRING_RESULT_CANCELLED);
 
-	mainloop_run (2000);
+	egg_test_wait ();
 
 	g_assert_cmpint (GNOME_KEYRING_RESULT_OK, ==, res);
 }
@@ -520,7 +501,7 @@ done_find_password (GnomeKeyringResult res, const gchar* password, gpointer unus
 		g_assert_cmpstr (password, ==, "password");
 	}
 
-	g_main_loop_quit (mainloop);
+	egg_test_wait_stop ();
 }
 
 static void
@@ -558,7 +539,7 @@ test_find_password (void)
 	/* "callback already called" */
 	g_assert (find_password_result == GNOME_KEYRING_RESULT_CANCELLED);
 
-	mainloop_run (2000);
+	egg_test_wait ();
 
 	g_assert_cmpint (GNOME_KEYRING_RESULT_OK, ==, find_password_result);
 }
@@ -570,7 +551,7 @@ done_find_no_password (GnomeKeyringResult res, const gchar* password, gpointer u
 {
 	find_no_password_result = res;
 	g_assert (password == NULL);
-	g_main_loop_quit (mainloop);
+	egg_test_wait_stop ();
 }
 
 static void
@@ -598,7 +579,7 @@ test_find_no_password (void)
 	g_assert (op != NULL);
 	g_assert (find_no_password_result == GNOME_KEYRING_RESULT_CANCELLED);
 
-	mainloop_run (2000);
+	egg_test_wait ();
 
 	g_assert_cmpint (GNOME_KEYRING_RESULT_NO_MATCH, ==, find_no_password_result);
 }
@@ -607,7 +588,7 @@ static void
 done_delete_password (GnomeKeyringResult res, gpointer data)
 {
 	*((GnomeKeyringResult*)data) = res;
-	g_main_loop_quit (mainloop);
+	egg_test_wait_stop ();
 }
 
 static void
@@ -638,7 +619,7 @@ test_delete_password (void)
 	/* "callback already called" */
 	g_assert (res == GNOME_KEYRING_RESULT_CANCELLED);
 
-	mainloop_run (2000);
+	egg_test_wait ();
 
 	/* Should have already been deleted by the second call above */
 	g_assert_cmpint (GNOME_KEYRING_RESULT_OK, ==, res);
@@ -694,8 +675,6 @@ main (int argc, char **argv)
 	if (service && service[0])
 		service = NULL;
 
-	mainloop = g_main_loop_new (NULL, FALSE);
-
 	g_test_add_func ("/keyrings/remove-incomplete", test_remove_incomplete);
 	g_test_add_func ("/keyrings/create-keyring", test_create_keyring);
 	g_test_add_func ("/keyrings/create-keyring-already-exists", test_create_keyring_already_exists);
@@ -729,7 +708,7 @@ main (int argc, char **argv)
 
 	}
 
-	ret = g_test_run ();
+	ret = egg_tests_run_with_loop ();
 	mock_service_stop ();
 
 	return ret;



[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]