[gcr] gcr: Make prompter tests work properly, add debugging



commit cf51303c1b38857d3aa04cece982d6e8e58fea5a
Author: Stef Walter <stefw collabora co uk>
Date:   Mon Oct 31 17:43:54 2011 +0100

    gcr: Make prompter tests work properly, add debugging
    
     * Run mock prompter in a separate thread to fix blocking
       and concurrency issues.
     * Run tests in in the main process thread
     * Add more debugging output

 .gitignore                     |    2 +
 egg/egg-error.h                |   10 +-
 egg/egg-testing.c              |   85 ++++++++-
 egg/egg-testing.h              |    2 +
 gcr/gcr-mock-prompter.c        |  332 +++++++++++++++++++++++++++++----
 gcr/gcr-mock-prompter.h        |   22 +--
 gcr/gcr-system-prompt.c        |  195 ++++++++++++++++++--
 gcr/gcr-system-prompt.h        |   16 ++-
 gcr/gcr-system-prompter.c      |   72 +++++---
 gcr/gcr-system-prompter.h      |    4 +-
 gcr/tests/frob-system-prompt.c |  106 +++++++++++
 gcr/tests/test-system-prompt.c |  409 ++++++++++++++++++++++++++++++++++++++++
 12 files changed, 1161 insertions(+), 94 deletions(-)
---
diff --git a/.gitignore b/.gitignore
index 4e4d3c7..3f5599f 100644
--- a/.gitignore
+++ b/.gitignore
@@ -83,9 +83,11 @@ stamp-*
 /gck/gck-marshal.*
 
 /gcr/*.pc
+/gcr/gcr-dbus-generated.*
 /gcr/gcr-enum-types*
 /gcr/gcr-oids.*
 /gcr/gcr-marshal.*
+/gcr/gcr-prompter
 /gcr/gcr-viewer
 /gcr/gcr-viewer.desktop
 
diff --git a/egg/egg-error.h b/egg/egg-error.h
index 50f459c..9e7b74e 100644
--- a/egg/egg-error.h
+++ b/egg/egg-error.h
@@ -24,11 +24,19 @@
 
 #include <glib.h>
 
-static inline const gchar*
+static inline const gchar *
 egg_error_message (GError *error)
 {
 	g_return_val_if_fail (error, "(unknown)");
 	return error->message ? error->message : "(null)";
 }
 
+static inline const gchar *
+egg_error_result_message (GError **error)
+{
+	if (error == NULL)
+		return "(unknown)";
+	return (*error) && (*error)->message ? (*error)->message : "(null)";
+}
+
 #endif /* EGG_ERROR_H_ */
diff --git a/egg/egg-testing.c b/egg/egg-testing.c
index 88d647d..e220fbd 100644
--- a/egg/egg-testing.c
+++ b/egg/egg-testing.c
@@ -105,6 +105,9 @@ egg_assertion_message_cmpmem (const char     *domain,
   g_free (s);
 }
 
+static void (*wait_stop_impl) (void);
+static gboolean (*wait_until_impl) (int timeout);
+
 void
 egg_assertion_not_object (const char *domain,
                           const char *file,
@@ -131,6 +134,20 @@ egg_assertion_not_object (const char *domain,
 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);
+}
+
+static void
+thread_wait_stop (void)
+{
 	GTimeVal tv;
 
 	g_get_current_time (&tv);
@@ -146,8 +163,8 @@ egg_test_wait_stop (void)
 	g_mutex_unlock (wait_mutex);
 }
 
-gboolean
-egg_test_wait_until (int timeout)
+static gboolean
+thread_wait_until (int timeout)
 {
 	GTimeVal tv;
 	gboolean ret;
@@ -169,11 +186,70 @@ egg_test_wait_until (int timeout)
 	return ret;
 }
 
+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 ret = FALSE;
+	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);
+
+	if (timed_out) {
+		g_source_remove (source);
+		ret = FALSE;
+	} else {
+		ret = TRUE;
+	}
+
+	g_main_loop_unref (wait_loop);
+	wait_loop = NULL;
+	return ret;
+
+	g_assert (wait_loop != NULL);
+	g_main_loop_quit (wait_loop);
+}
+
 static gpointer
 testing_thread (gpointer loop)
 {
-	/* Must have been defined by the test including this file */
-	gint ret = g_test_run ();
+	gint ret;
+
+	wait_stop_impl = thread_wait_stop;
+	wait_until_impl = thread_wait_until;
+
+	ret = g_test_run ();
+
+	wait_stop_impl = NULL;
+	wait_until_impl = NULL;
+
+	/* Quit the main loop now that tests are done */
 	g_main_loop_quit (loop);
 	return GINT_TO_POINTER (ret);
 }
@@ -205,6 +281,7 @@ egg_tests_run_with_loop (void)
 
 	return GPOINTER_TO_INT (ret);
 }
+<<<<<<< HEAD
 #endif
 
 
diff --git a/egg/egg-testing.h b/egg/egg-testing.h
index a15925a..0995e4d 100644
--- a/egg/egg-testing.h
+++ b/egg/egg-testing.h
@@ -73,4 +73,6 @@ gboolean   egg_test_wait_until                 (int timeout);
 
 gint       egg_tests_run_with_loop             (void);
 
+gint       egg_tests_run_with_loop             (void);
+
 #endif /* EGG_DH_H_ */
diff --git a/gcr/gcr-mock-prompter.c b/gcr/gcr-mock-prompter.c
index 412c101..836ef35 100644
--- a/gcr/gcr-mock-prompter.c
+++ b/gcr/gcr-mock-prompter.c
@@ -51,34 +51,62 @@
  * The class for #GcrMockPrompter.
  */
 
+
+GType   gcr_mock_prompter_get_type        (void) G_GNUC_CONST;
+#define GCR_TYPE_MOCK_PROMPTER            (gcr_mock_prompter_get_type ())
+#define GCR_MOCK_PROMPTER(obj)            (G_TYPE_CHECK_INSTANCE_CAST ((obj), GCR_TYPE_MOCK_PROMPTER, GcrMockPrompter))
+#define GCR_IS_MOCK_PROMPTER(obj)         (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GCR_TYPE_MOCK_PROMPTER))
 #define GCR_IS_MOCK_PROMPTER_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), GCR_TYPE_MOCK_PROMPTER))
 #define GCR_MOCK_PROMPTER_CLASS(klass)    (G_TYPE_CHECK_CLASS_CAST ((klass), GCR_TYPE_MOCK_PROMPTER, GcrMockPromptClass))
 #define GCR_MOCK_PROMPTER_GET_CLASS(obj)  (G_TYPE_INSTANCE_GET_CLASS ((obj), GCR_TYPE_MOCK_PROMPTER, GcrMockPromptClass))
 
+typedef struct _GcrMockPrompter GcrMockPrompter;
 typedef struct _GcrMockPrompterClass GcrMockPrompterClass;
 typedef struct _GcrMockPrompterPrivate GcrMockPrompterPrivate;
 
 enum {
 	PROP_0,
 	PROP_CONNECTION,
+	PROP_SHOWING,
+	PROP_DELAY_MSEC
 };
 
-typedef struct {
-	gboolean proceed;
-	gchar *password;
-	GList *properties;
-} MockResponse;
-
 struct _GcrMockPrompter {
 	GcrSystemPrompter parent;
 	GDBusConnection *connection;
 	GQueue *responses;
+	gboolean showing;
+	guint delay_msec;
+	guint delay_source;
 };
 
 struct _GcrMockPrompterClass {
 	GcrSystemPrompterClass parent_class;
 };
 
+typedef struct {
+	gboolean proceed;
+	gchar *password;
+	GList *properties;
+
+	/* Used while responding */
+	GcrMockPrompter *prompter;
+} MockResponse;
+
+typedef struct {
+	/* Owned by the calling thread */
+	GMutex *mutex;
+	GCond *start_cond;
+	GThread *thread;
+
+	/* Owned by the prompter thread*/
+	GcrMockPrompter *prompter;
+	const gchar *bus_name;
+	GMainLoop *loop;
+} ThreadData;
+
+static ThreadData *running = NULL;
+
 G_DEFINE_TYPE (GcrMockPrompter, gcr_mock_prompter, GCR_TYPE_SYSTEM_PROMPTER);
 
 static void
@@ -95,6 +123,8 @@ mock_response_free (gpointer data)
 	MockResponse *response = data;
 	g_free (response->password);
 	g_list_free_full (response->properties, mock_property_free);
+	g_clear_object (&response->prompter);
+	g_free (response);
 }
 
 static void
@@ -115,6 +145,9 @@ gcr_mock_prompter_set_property (GObject *obj,
 	case PROP_CONNECTION:
 		self->connection = g_value_get_object (value);
 		break;
+	case PROP_DELAY_MSEC:
+		self->delay_msec = g_value_get_uint (value);
+		break;
 	default:
 		G_OBJECT_WARN_INVALID_PROPERTY_ID (obj, prop_id, pspec);
 		break;
@@ -133,6 +166,12 @@ gcr_mock_prompter_get_property (GObject *obj,
 	case PROP_CONNECTION:
 		g_value_set_object (value, self->connection);
 		break;
+	case PROP_SHOWING:
+		g_value_set_boolean (value, self->showing);
+		break;
+	case PROP_DELAY_MSEC:
+		g_value_set_uint (value, self->delay_msec);
+		break;
 	default:
 		G_OBJECT_WARN_INVALID_PROPERTY_ID (obj, prop_id, pspec);
 		break;
@@ -146,6 +185,11 @@ gcr_mock_prompter_dispose (GObject *obj)
 	GcrMockPrompter *self = GCR_MOCK_PROMPTER (obj);
 	MockResponse *response;
 
+	if (self->delay_source) {
+		g_source_remove (self->delay_source);
+		self->delay_source = 0;
+	}
+
 	if (self->connection) {
 		gcr_system_prompter_unregister (GCR_SYSTEM_PROMPTER (self), self->connection);
 		g_object_remove_weak_pointer (G_OBJECT (self->connection),
@@ -251,6 +295,42 @@ prompter_set_properties (GcrMockPrompter *self,
 	}
 }
 
+static void
+gcr_mock_prompter_open (GcrSystemPrompter *prompter)
+{
+	GcrMockPrompter *self = GCR_MOCK_PROMPTER (prompter);
+	self->showing = TRUE;
+}
+
+static void
+gcr_mock_prompter_close (GcrSystemPrompter *prompter)
+{
+	GcrMockPrompter *self = GCR_MOCK_PROMPTER (prompter);
+
+	if (self->delay_source != 0) {
+		g_source_remove (self->delay_source);
+		self->delay_source = 0;
+	}
+
+	self->showing = FALSE;
+}
+
+static gboolean
+on_timeout_prompt_confirm (gpointer data)
+{
+	MockResponse *response = data;
+	GcrSystemPrompter *prompter = GCR_SYSTEM_PROMPTER (response->prompter);
+
+	response->prompter->delay_source = 0;
+
+	if (!response->proceed)
+		gcr_system_prompter_respond_cancelled (prompter);
+	else
+		gcr_system_prompter_respond_confirmed (prompter);
+
+	return FALSE;
+}
+
 static gboolean
 gcr_mock_prompter_prompt_confirm (GcrSystemPrompter *prompter)
 {
@@ -268,14 +348,35 @@ gcr_mock_prompter_prompt_confirm (GcrSystemPrompter *prompter)
 	}
 
 	prompter_set_properties (self, response->properties);
+	response->prompter = g_object_ref (prompter);
+
+	if (self->delay_msec > 0) {
+		g_assert (!self->delay_source);
+		self->delay_source = g_timeout_add_full (G_PRIORITY_DEFAULT, self->delay_msec,
+		                                         on_timeout_prompt_confirm,
+		                                         response, mock_response_free);
+	} else {
+		on_timeout_prompt_confirm (response);
+		mock_response_free (response);
+	}
+
+	return TRUE;
+}
+
+static gboolean
+on_timeout_prompt_password (gpointer data)
+{
+	MockResponse *response = data;
+	GcrSystemPrompter *prompter = GCR_SYSTEM_PROMPTER (response->prompter);
+
+	response->prompter->delay_source = 0;
 
 	if (!response->proceed)
-		gcr_system_prompter_respond_cancelled (GCR_SYSTEM_PROMPTER (self));
+		gcr_system_prompter_respond_cancelled (prompter);
 	else
-		gcr_system_prompter_respond_confirmed (GCR_SYSTEM_PROMPTER (self));
+		gcr_system_prompter_respond_with_password (prompter, response->password);
 
-	mock_response_free (response);
-	return TRUE;
+	return FALSE;
 }
 
 static gboolean
@@ -296,13 +397,18 @@ gcr_mock_prompter_prompt_password (GcrSystemPrompter *prompter)
 	}
 
 	prompter_set_properties (self, response->properties);
+	response->prompter = g_object_ref (prompter);
+
+	if (self->delay_msec > 0) {
+		g_assert (!self->delay_source);
+		self->delay_source = g_timeout_add_full (G_PRIORITY_DEFAULT, self->delay_msec,
+		                                         on_timeout_prompt_password,
+		                                         response, mock_response_free);
+	} else {
+		on_timeout_prompt_password (response);
+		mock_response_free (response);
+	}
 
-	if (!response->proceed)
-		gcr_system_prompter_respond_cancelled (GCR_SYSTEM_PROMPTER (self));
-	else
-		gcr_system_prompter_respond_with_password (GCR_SYSTEM_PROMPTER (self), response->password);
-
-	mock_response_free (response);
 	return TRUE;
 }
 
@@ -317,12 +423,22 @@ gcr_mock_prompter_class_init (GcrMockPrompterClass *klass)
 	gobject_class->dispose = gcr_mock_prompter_dispose;
 	gobject_class->finalize = gcr_mock_prompter_finalize;
 
+	prompter_class->open = gcr_mock_prompter_open;
+	prompter_class->close = gcr_mock_prompter_close;
 	prompter_class->prompt_password= gcr_mock_prompter_prompt_password;
 	prompter_class->prompt_confirm = gcr_mock_prompter_prompt_confirm;
 
 	g_object_class_install_property (gobject_class, PROP_CONNECTION,
 	            g_param_spec_object ("connection", "Connection", "DBus connection",
 	                                 G_TYPE_DBUS_CONNECTION, G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY));
+
+	g_object_class_install_property (gobject_class, PROP_SHOWING,
+	            g_param_spec_boolean ("showing", "Showing", "Whether showing a prompt",
+	                                  FALSE, G_PARAM_READABLE));
+
+	g_object_class_install_property (gobject_class, PROP_DELAY_MSEC,
+	              g_param_spec_uint ("delay-msec", "Delay msec", "Prompt delay in milliseconds",
+	                                 0, G_MAXUINT, 0, G_PARAM_READWRITE));
 }
 
 static GList *
@@ -375,82 +491,224 @@ build_properties (GcrMockPrompter *self,
 	return result;
 }
 
+gboolean
+gcr_mock_prompter_get_showing (void)
+{
+	gboolean showing = FALSE;
+
+	g_assert (running != NULL);
+	g_mutex_lock (running->mutex);
+	g_object_get (running->prompter, "showing", &showing, NULL);
+	g_mutex_unlock (running->mutex);
+
+	return showing;
+}
+
+guint
+gcr_mock_prompter_get_delay_msec (void)
+{
+	guint delay_msec;
+
+	g_assert (running != NULL);
+	g_mutex_lock (running->mutex);
+	g_object_get (running->prompter, "delay-msec", &delay_msec, NULL);
+	g_mutex_unlock (running->mutex);
+
+	return delay_msec;
+}
+
+void
+gcr_mock_prompter_set_delay_msec (guint delay_msec)
+{
+	g_assert (running != NULL);
+	g_mutex_lock (running->mutex);
+	g_object_set (running->prompter, "delay-msec", delay_msec, NULL);
+	g_mutex_unlock (running->mutex);
+}
+
 void
-gcr_mock_prompter_expect_confirm_ok (GcrMockPrompter *self,
-                                     const gchar *first_property_name,
+gcr_mock_prompter_expect_confirm_ok (const gchar *first_property_name,
                                      ...)
 {
 	MockResponse *response;
 	va_list var_args;
 
-	g_return_if_fail (GCR_IS_MOCK_PROMPTER (self));
+	g_assert (running != NULL);
+
+	g_mutex_lock (running->mutex);
 
 	response = g_new0 (MockResponse, 1);
 	response->password = NULL;
 	response->proceed = TRUE;
 
 	va_start (var_args, first_property_name);
-	response->properties = build_properties (self, first_property_name, var_args);
+	response->properties = build_properties (running->prompter, first_property_name, var_args);
 	va_end (var_args);
 
-	g_queue_push_tail (self->responses, response);
+	g_queue_push_tail (running->prompter->responses, response);
+	g_mutex_unlock (running->mutex);
 }
 
 void
-gcr_mock_prompter_expect_confirm_cancel (GcrMockPrompter *self)
+gcr_mock_prompter_expect_confirm_cancel (void)
 {
 	MockResponse *response;
 
-	g_return_if_fail (GCR_IS_MOCK_PROMPTER (self));
+	g_assert (running != NULL);
+
+	g_mutex_lock (running->mutex);
 
 	response = g_new0 (MockResponse, 1);
 	response->password = NULL;
 	response->proceed = FALSE;
 
-	g_queue_push_tail (self->responses, response);
+	g_queue_push_tail (running->prompter->responses, response);
 
+	g_mutex_unlock (running->mutex);
 }
 
 void
-gcr_mock_prompter_expect_password_ok (GcrMockPrompter *self,
-                                      const gchar *password,
+gcr_mock_prompter_expect_password_ok (const gchar *password,
                                       const gchar *first_property_name,
                                       ...)
 {
 	MockResponse *response;
 	va_list var_args;
 
-	g_return_if_fail (GCR_IS_MOCK_PROMPTER (self));
-	g_return_if_fail (password != NULL);
+	g_assert (running != NULL);
+	g_assert (password != NULL);
+
+	g_mutex_lock (running->mutex);
 
 	response = g_new0 (MockResponse, 1);
 	response->password = g_strdup (password);
 	response->proceed = TRUE;
 
 	va_start (var_args, first_property_name);
-	response->properties = build_properties (self, first_property_name, var_args);
+	response->properties = build_properties (running->prompter, first_property_name, var_args);
 	va_end (var_args);
 
-	g_queue_push_tail (self->responses, response);
+	g_queue_push_tail (running->prompter->responses, response);
+
+	g_mutex_unlock (running->mutex);
 }
 
 void
-gcr_mock_prompter_expect_password_cancel (GcrMockPrompter *self)
+gcr_mock_prompter_expect_password_cancel (void)
 {
 	MockResponse *response;
 
-	g_return_if_fail (GCR_IS_MOCK_PROMPTER (self));
+	g_assert (running != NULL);
+
+	g_mutex_lock (running->mutex);
 
 	response = g_new0 (MockResponse, 1);
 	response->password = g_strdup ("");
 	response->proceed = FALSE;
 
-	g_queue_push_tail (self->responses, response);
+	g_queue_push_tail (running->prompter->responses, response);
+
+	g_mutex_unlock (running->mutex);
+}
+
+static gpointer
+mock_prompter_thread (gpointer data)
+{
+	ThreadData *thread_data = data;
+	GDBusConnection *connection;
+	GMainContext *context;
+	GError *error = NULL;
+	gchar *address;
+
+	g_mutex_lock (thread_data->mutex);
+	context = g_main_context_new ();
+	g_main_context_push_thread_default (context);
+
+	thread_data->prompter = g_object_new (GCR_TYPE_MOCK_PROMPTER, NULL);
+
+	address = g_dbus_address_get_for_bus_sync (G_BUS_TYPE_SESSION, NULL, &error);
+	if (error == NULL) {
+		connection = g_dbus_connection_new_for_address_sync (address,
+		                                                     G_DBUS_CONNECTION_FLAGS_AUTHENTICATION_CLIENT |
+		                                                     G_DBUS_CONNECTION_FLAGS_MESSAGE_BUS_CONNECTION,
+		                                                     NULL, NULL, &error);
+		if (error == NULL) {
+			gcr_system_prompter_register (GCR_SYSTEM_PROMPTER (thread_data->prompter),
+			                              connection);
+			thread_data->bus_name = g_dbus_connection_get_unique_name (connection);
+		}
+
+		g_free (address);
+	}
+
+	if (error != NULL) {
+		g_critical ("mock prompter couldn't get session bus address: %s",
+		            egg_error_message (error));
+		g_clear_error (&error);
+	}
+
+	thread_data->loop = g_main_loop_new (context, FALSE);
+	g_cond_signal (thread_data->start_cond);
+	g_mutex_unlock (thread_data->mutex);
+
+	g_main_loop_run (thread_data->loop);
+
+	g_mutex_lock (thread_data->mutex);
+	g_main_context_pop_thread_default (context);
+	g_main_context_unref (context);
+
+	if (connection) {
+		gcr_system_prompter_unregister (GCR_SYSTEM_PROMPTER (thread_data->prompter),
+		                                connection);
+		g_object_unref (connection);
+	}
+
+	g_mutex_unlock (thread_data->mutex);
+	return thread_data;
 }
 
-GcrMockPrompter *
-gcr_mock_prompter_new ()
+const gchar *
+gcr_mock_prompter_start (void)
 {
-	return g_object_new (GCR_TYPE_MOCK_PROMPTER,
-	                     NULL);
+	GError *error = NULL;
+
+	g_assert (running == NULL);
+
+	running = g_new0 (ThreadData, 1);
+	running->mutex = g_mutex_new ();
+	running->start_cond = g_cond_new ();
+
+	g_mutex_lock (running->mutex);
+	running->thread = g_thread_create (mock_prompter_thread, running, TRUE, &error);
+
+	if (error != NULL)
+		g_error ("mock prompter couldn't start thread: %s", error->message);
+
+	g_cond_wait (running->start_cond, running->mutex);
+	g_assert (running->loop);
+	g_assert (running->prompter);
+	g_mutex_unlock (running->mutex);
+
+	return running->bus_name;
+}
+
+void
+gcr_mock_prompter_stop (void)
+{
+	ThreadData *check;
+
+	g_assert (running != NULL);
+
+	g_mutex_lock (running->mutex);
+	g_assert (running->loop != NULL);
+	g_main_loop_quit (running->loop);
+	g_mutex_unlock (running->mutex);
+
+	check = g_thread_join (running->thread);
+	g_assert (check == running);
+
+	g_cond_free (running->start_cond);
+	g_mutex_free (running->mutex);
+	g_free (running);
+	running = NULL;
 }
diff --git a/gcr/gcr-mock-prompter.h b/gcr/gcr-mock-prompter.h
index 4b5f302..f2068ec 100644
--- a/gcr/gcr-mock-prompter.h
+++ b/gcr/gcr-mock-prompter.h
@@ -34,28 +34,26 @@
 
 G_BEGIN_DECLS
 
-#define GCR_TYPE_MOCK_PROMPTER            (gcr_mock_prompter_get_type ())
-#define GCR_MOCK_PROMPTER(obj)            (G_TYPE_CHECK_INSTANCE_CAST ((obj), GCR_TYPE_MOCK_PROMPTER, GcrMockPrompter))
-#define GCR_IS_MOCK_PROMPTER(obj)         (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GCR_TYPE_MOCK_PROMPTER))
+const gchar *        gcr_mock_prompter_start                     (void);
 
-typedef struct _GcrMockPrompter GcrMockPrompter;
+void                 gcr_mock_prompter_stop                      (void);
 
-GType                gcr_mock_prompter_get_type                  (void) G_GNUC_CONST;
+gboolean             gcr_mock_prompter_get_showing               (void);
 
-GcrMockPrompter *    gcr_mock_prompter_new                       (void);
+guint                gcr_mock_prompter_get_delay_msec            (void);
 
-void                 gcr_mock_prompter_expect_confirm_ok         (GcrMockPrompter *self,
-                                                                  const gchar *property_name,
+void                 gcr_mock_prompter_set_delay_msec            (guint delay_msec);
+
+void                 gcr_mock_prompter_expect_confirm_ok         (const gchar *property_name,
                                                                   ...);
 
-void                 gcr_mock_prompter_expect_confirm_cancel     (GcrMockPrompter *self);
+void                 gcr_mock_prompter_expect_confirm_cancel     (void);
 
-void                 gcr_mock_prompter_expect_password_ok        (GcrMockPrompter *self,
-                                                                  const gchar *password,
+void                 gcr_mock_prompter_expect_password_ok        (const gchar *password,
                                                                   const gchar *property_name,
                                                                   ...);
 
-void                 gcr_mock_prompter_expect_password_cancel    (GcrMockPrompter *self);
+void                 gcr_mock_prompter_expect_password_cancel    (void);
 
 G_END_DECLS
 
diff --git a/gcr/gcr-system-prompt.c b/gcr/gcr-system-prompt.c
index 5caac14..43868d7 100644
--- a/gcr/gcr-system-prompt.c
+++ b/gcr/gcr-system-prompt.c
@@ -25,11 +25,15 @@
 
 #include "gcr-dbus-constants.h"
 #include "gcr-dbus-generated.h"
+#define DEBUG_FLAG GCR_DEBUG_PROMPT
+#include "gcr-debug.h"
 #include "gcr-internal.h"
 #include "gcr-library.h"
 #include "gcr-secret-exchange.h"
 #include "gcr-system-prompt.h"
 
+#include "egg/egg-error.h"
+
 /**
  * SECTION:gcr-system-prompt
  * @title: GcrSystemPrompt
@@ -205,12 +209,14 @@ gcr_system_prompt_dispose (GObject *obj)
 	g_clear_object (&self->pv->exchange);
 
 	if (self->pv->prompt_path) {
+		_gcr_debug ("closing prompt asynchronously: %s", self->pv->prompt_path);
+
 		g_dbus_connection_call (self->pv->connection,
 		                        self->pv->prompter_bus_name,
 		                        GCR_DBUS_PROMPTER_OBJECT_PATH,
 		                        GCR_DBUS_PROMPTER_INTERFACE,
 		                        GCR_DBUS_PROMPTER_METHOD_FINISH,
-		                        g_variant_new ("()"),
+		                        g_variant_new ("(o)", self->pv->prompt_path),
 		                        NULL, G_DBUS_CALL_FLAGS_NO_AUTO_START,
 		                        -1, NULL, NULL, NULL);
 		g_free (self->pv->prompt_path);
@@ -315,8 +321,10 @@ gcr_system_prompt_get_secret_exchange (GcrSystemPrompt *self)
 {
 	g_return_val_if_fail (GCR_IS_SYSTEM_PROMPT (self), NULL);
 
-	if (!self->pv->exchange)
+	if (!self->pv->exchange) {
+		_gcr_debug ("creating new secret exchange");
 		self->pv->exchange = gcr_secret_exchange_new (NULL);
+	}
 
 	return self->pv->exchange;
 }
@@ -554,10 +562,16 @@ gcr_system_prompt_real_init (GInitable *initable,
 
 	/* 1. Connect to the session bus */
 	if (!self->pv->connection) {
+
 		self->pv->connection = g_bus_get_sync (G_BUS_TYPE_SESSION,
 		                                       cancellable, error);
-		if (self->pv->connection == NULL)
+		if (self->pv->connection == NULL) {
+			_gcr_debug ("failed to connect to bus: %s",
+			            egg_error_result_message (error));
 			return FALSE;
+		}
+
+		_gcr_debug ("connected to bus");
 	}
 
 	/* 2. Tell the prompter we want to begin prompting */
@@ -573,13 +587,18 @@ gcr_system_prompt_real_init (GInitable *initable,
 		                                   G_VARIANT_TYPE ("(o)"),
 		                                   G_DBUS_CALL_FLAGS_NONE,
 		                                   -1, cancellable, error);
-		if (ret == NULL)
+		if (ret == NULL) {
+			_gcr_debug ("failed to open prompt: %s",
+			            egg_error_result_message (error));
 			return FALSE;
+		}
 
 		self->pv->begun_prompting = TRUE;
 		g_assert (self->pv->prompt_path == NULL);
 		g_variant_get (ret, "(o)", &self->pv->prompt_path);
 		g_variant_unref (ret);
+
+		_gcr_debug ("opened prompt: %s", self->pv->prompt_path);
 	}
 
 	/* 3. Create a dbus proxy */
@@ -591,10 +610,14 @@ gcr_system_prompt_real_init (GInitable *initable,
 		                                                self->pv->prompt_path,
 		                                                GCR_DBUS_PROMPT_INTERFACE,
 		                                                cancellable, error);
-		if (self->pv->prompt_proxy == NULL)
+		if (self->pv->prompt_proxy == NULL) {
+			_gcr_debug ("failed to create prompt proxy: %s",
+			            egg_error_result_message (error));
 			return FALSE;
+		}
 
 		g_dbus_proxy_set_default_timeout (self->pv->prompt_proxy, G_MAXINT);
+		_gcr_debug ("created prompt proxy");
 	}
 
 	return TRUE;
@@ -633,9 +656,12 @@ on_bus_connected (GObject *source,
 
 	if (error == NULL) {
 		g_return_if_fail (self->pv->connection != NULL);
+
+		_gcr_debug ("connected to bus");
 		perform_init_async (self, res);
 
 	} else {
+		_gcr_debug ("failed to connect to bus: %s", egg_error_message (error));
 		g_simple_async_result_take_error (res, error);
 		g_simple_async_result_complete (res);
 	}
@@ -662,10 +688,14 @@ on_prompter_begin_prompting (GObject *source,
 		g_variant_get (ret, "(o)", &self->pv->prompt_path);
 		g_variant_unref (ret);
 
+		_gcr_debug ("opened prompt: %s", self->pv->prompt_path);
+
 		g_return_if_fail (self->pv->prompt_path != NULL);
 		perform_init_async (self, res);
 
 	} else {
+		_gcr_debug ("failed to open prompt: %s", egg_error_message (error));
+
 		g_simple_async_result_take_error (res, error);
 		g_simple_async_result_complete (res);
 	}
@@ -687,11 +717,16 @@ on_prompt_proxy_new (GObject *source,
 	self->pv->prompt_proxy = g_dbus_proxy_new_finish (result, &error);
 
 	if (error == NULL) {
+		_gcr_debug ("created prompt proxy");
+
 		g_return_if_fail (self->pv->prompt_proxy != NULL);
 		perform_init_async (self, res);
 
 	} else {
+		_gcr_debug ("failed to create prompt proxy: %s", egg_error_message (error));
+
 		g_simple_async_result_take_error (res, error);
+		g_simple_async_result_complete (res);
 	}
 
 	g_object_unref (self);
@@ -706,11 +741,13 @@ perform_init_async (GcrSystemPrompt *self,
 
 	/* 1. Connect to the session bus */
 	if (!self->pv->connection) {
+		_gcr_debug ("connecting to bus");
 		g_bus_get (G_BUS_TYPE_SESSION, closure->cancellable,
 		           on_bus_connected, g_object_ref (res));
 
 	/* 2. Tell the prompter we want to begin prompting */
 	} else if (!self->pv->prompt_path) {
+		_gcr_debug ("opening prompt");
 		g_dbus_connection_call (self->pv->connection,
 		                        self->pv->prompter_bus_name,
 		                        GCR_DBUS_PROMPTER_OBJECT_PATH,
@@ -725,6 +762,7 @@ perform_init_async (GcrSystemPrompt *self,
 
 	/* 3. Create a dbus proxy */
 	} else if (!self->pv->prompt_proxy) {
+		_gcr_debug ("creating prompt proxy");
 		g_dbus_proxy_new (self->pv->connection,
 		                  G_DBUS_PROXY_FLAGS_DO_NOT_AUTO_START,
 		                  _gcr_prompter_prompt_interface_info (),
@@ -735,9 +773,11 @@ perform_init_async (GcrSystemPrompt *self,
 		                  on_prompt_proxy_new,
 		                  g_object_ref (res));
 
+	/* 4. All done */
+	} else {
+		_gcr_debug ("successfully initialized prompt");
+		g_simple_async_result_complete (res);
 	}
-
-	g_simple_async_result_complete (res);
 }
 
 static void
@@ -799,6 +839,7 @@ parameter_properties (GcrSystemPrompt *self)
 
 	g_hash_table_iter_init (&iter, self->pv->properties_to_write);
 	while (g_hash_table_iter_next (&iter, (gpointer *)&property_name, NULL)) {
+		_gcr_debug ("sending prompt property: %s", property_name);
 		variant = g_hash_table_lookup (self->pv->property_cache, property_name);
 		if (variant == NULL)
 			g_warning ("couldn't find prompt property to write: %s", property_name);
@@ -823,6 +864,7 @@ return_properties (GcrSystemPrompt *self,
 
 	g_variant_get (properties, "a(ssv)", &iter);
 	while (g_variant_iter_loop (iter, "(ssv)", &interface, &property_name, &value)) {
+		_gcr_debug ("received prompt property: %s", property_name);
 		key = (gpointer)g_intern_string (property_name);
 		if (!g_hash_table_lookup (self->pv->properties_to_write, key)) {
 			g_hash_table_insert (self->pv->property_cache,
@@ -842,10 +884,13 @@ parameters_for_password (GcrSystemPrompt *self)
 
 	exchange = gcr_system_prompt_get_secret_exchange (self);
 
-	if (self->pv->exchanged)
+	if (self->pv->exchanged) {
+		_gcr_debug ("sending secret exchange");
 		input = gcr_secret_exchange_send (exchange, NULL, 0);
-	else
+	} else {
+		_gcr_debug ("beginning secret exchange");
 		input = gcr_secret_exchange_begin (exchange);
+	}
 	self->pv->exchanged = TRUE;
 
 	properties = parameter_properties (self);
@@ -872,11 +917,15 @@ return_for_password (GcrSystemPrompt *self,
 
 	if (output && output[0]) {
 		if (!gcr_secret_exchange_receive (exchange, output)) {
+			_gcr_debug ("received invalid secret exchange");
 			g_set_error (error, GCR_SYSTEM_PROMPT_ERROR,
 			             GCR_SYSTEM_PROMPT_FAILED, "Invalid secret exchanged");
 		} else {
+			_gcr_debug ("received password in secret exchange");
 			ret = gcr_secret_exchange_get_secret (exchange, NULL);
 		}
+	} else {
+		_gcr_debug ("password prompt was cancelled");
 	}
 
 	g_variant_unref (properties);
@@ -904,8 +953,10 @@ on_prompt_requested_password (GObject *source,
 		g_variant_unref (retval);
 	}
 
-	if (error != NULL)
+	if (error != NULL) {
+		_gcr_debug ("failed to prompt for password: %s", egg_error_message (error));
 		g_simple_async_result_take_error (res, error);
+	}
 
 	g_simple_async_result_complete (res);
 	g_object_unref (self);
@@ -926,6 +977,8 @@ gcr_system_prompt_password_async (GcrSystemPrompt *self,
 	res = g_simple_async_result_new (G_OBJECT (self), callback, user_data,
 	                                 gcr_system_prompt_password_async);
 
+	_gcr_debug ("prompting for password");
+
 	g_dbus_proxy_call (G_DBUS_PROXY (self->pv->prompt_proxy),
 	                   GCR_DBUS_PROMPT_METHOD_PASSWORD,
 	                   parameters_for_password (self),
@@ -970,6 +1023,8 @@ gcr_system_prompt_password (GcrSystemPrompt *self,
 		return NULL;
 	}
 
+	_gcr_debug ("prompting for password");
+
 	retval = g_dbus_proxy_call_sync (self->pv->prompt_proxy,
 	                                 GCR_DBUS_PROMPT_METHOD_PASSWORD,
 	                                 parameters_for_password (self),
@@ -1007,6 +1062,11 @@ return_for_confirm (GcrSystemPrompt *self,
 
 	g_variant_unref (properties);
 
+	if (confirm)
+		_gcr_debug ("prompt confirmed");
+	else
+		_gcr_debug ("prompt was cancelled");
+
 	return confirm;
 }
 
@@ -1028,8 +1088,10 @@ on_prompt_requested_confirm (GObject *source,
 		g_simple_async_result_set_op_res_gboolean (res, ret);
 	}
 
-	if (error != NULL)
+	if (error != NULL) {
+		_gcr_debug ("failed to prompt for confirm: %s", egg_error_message (error));
 		g_simple_async_result_take_error (res, error);
+	}
 
 	g_simple_async_result_complete (res);
 	g_object_unref (self);
@@ -1057,6 +1119,8 @@ gcr_system_prompt_confirm_async (GcrSystemPrompt *self,
 	res = g_simple_async_result_new (G_OBJECT (self), callback, user_data,
 	                                 gcr_system_prompt_confirm_async);
 
+	_gcr_debug ("prompting for confirm");
+
 	g_dbus_proxy_call (G_DBUS_PROXY (self->pv->prompt_proxy),
 	                   GCR_DBUS_PROMPT_METHOD_CONFIRM,
 	                   parameters_for_confirm (self),
@@ -1118,6 +1182,8 @@ gcr_system_prompt_confirm (GcrSystemPrompt *self,
 		return FALSE;
 	}
 
+	_gcr_debug ("prompting for confirm");
+
 	retval = g_dbus_proxy_call_sync (self->pv->prompt_proxy,
 	                                 GCR_DBUS_PROMPT_METHOD_CONFIRM,
 	                                 parameters_for_confirm (self),
@@ -1190,6 +1256,11 @@ gcr_system_prompt_open_for_prompter_async (const gchar *prompter_name,
 	g_return_if_fail (timeout_seconds >= -1);
 	g_return_if_fail (cancellable == NULL || G_CANCELLABLE (cancellable));
 
+	if (prompter_name == NULL)
+		_gcr_debug ("opening prompt");
+	else
+		_gcr_debug ("opening prompt for prompter: %s", prompter_name);
+
 	g_async_initable_new_async (GCR_TYPE_SYSTEM_PROMPT,
 	                            G_PRIORITY_DEFAULT,
 	                            cancellable,
@@ -1294,6 +1365,11 @@ gcr_system_prompt_open_for_prompter (const gchar *prompter_name,
 	g_return_val_if_fail (cancellable == NULL || G_IS_CANCELLABLE (cancellable), NULL);
 	g_return_val_if_fail (error == NULL || *error == NULL, NULL);
 
+	if (prompter_name == NULL)
+		_gcr_debug ("opening prompt");
+	else
+		_gcr_debug ("opening prompt for prompter: %s", prompter_name);
+
 	return g_initable_new (GCR_TYPE_SYSTEM_PROMPT, cancellable, error,
 	                       "timeout-seconds", timeout_seconds,
 	                       "bus-name", prompter_name,
@@ -1308,12 +1384,103 @@ gcr_system_prompt_open_for_prompter (const gchar *prompter_name,
  * called on this object. The prompt object is not unreferenced by this
  * function, and you must unreference it once done.
  */
+gboolean
+gcr_system_prompt_close (GcrSystemPrompt *self,
+                         GCancellable *cancellable,
+                         GError **error)
+{
+	GVariant *retval;
+
+	g_return_val_if_fail (GCR_IS_SYSTEM_PROMPT (self), FALSE);
+	g_return_val_if_fail (cancellable == NULL || G_IS_CANCELLABLE (cancellable), FALSE);
+	g_return_val_if_fail (error == NULL || *error == NULL, FALSE);
+	g_return_val_if_fail (self->pv->prompt_path != NULL, FALSE);
+
+	_gcr_debug ("closing prompt");
+
+	retval = g_dbus_connection_call_sync (self->pv->connection,
+	                                      self->pv->prompter_bus_name,
+	                                      GCR_DBUS_PROMPTER_OBJECT_PATH,
+	                                      GCR_DBUS_PROMPTER_INTERFACE,
+	                                      GCR_DBUS_PROMPTER_METHOD_FINISH,
+	                                      g_variant_new ("(o)", self->pv->prompt_path),
+	                                      NULL, G_DBUS_CALL_FLAGS_NO_AUTO_START,
+	                                      -1, cancellable, error);
+	if (retval == NULL) {
+		_gcr_debug ("failed to close prompt: %s",
+		            egg_error_result_message (error));
+		return FALSE;
+	}
+
+	g_variant_unref (retval);
+	g_free (self->pv->prompt_path);
+	self->pv->prompt_path = NULL;
+	return TRUE;
+}
+
+static void
+on_prompt_close_async (GObject *source,
+                       GAsyncResult *result,
+                       gpointer user_data)
+{
+	GSimpleAsyncResult *res = G_SIMPLE_ASYNC_RESULT (user_data);
+	GcrSystemPrompt *self = GCR_SYSTEM_PROMPT (g_async_result_get_source_object (user_data));
+	GError *error = NULL;
+
+	if (!g_dbus_connection_call_finish (self->pv->connection, result, &error)) {
+		_gcr_debug ("failed to close prompt: %s", egg_error_message (error));
+		g_simple_async_result_take_error (res, error);
+	}
+
+	g_simple_async_result_complete (res);
+	g_object_unref (self);
+	g_object_unref (res);
+}
+
 void
-gcr_system_prompt_close (GcrSystemPrompt *self)
+gcr_system_prompt_close_async (GcrSystemPrompt *self,
+                               GCancellable *cancellable,
+                               GAsyncReadyCallback callback,
+                               gpointer user_data)
 {
-	g_return_if_fail (GCR_IS_SYSTEM_PROMPT (self));
+	GSimpleAsyncResult *res;
+
+	g_return_if_fail (GCR_SYSTEM_PROMPT (self));
+	g_return_if_fail (cancellable == NULL || G_IS_CANCELLABLE (cancellable));
+	g_return_if_fail (self->pv->prompt_path != NULL);
+
+	res = g_simple_async_result_new (G_OBJECT (self), callback, user_data,
+	                                 gcr_system_prompt_close_async);
+
+	_gcr_debug ("closing prompt");
+
+	g_dbus_connection_call (self->pv->connection,
+	                        self->pv->prompter_bus_name,
+	                        GCR_DBUS_PROMPTER_OBJECT_PATH,
+	                        GCR_DBUS_PROMPTER_INTERFACE,
+	                        GCR_DBUS_PROMPTER_METHOD_FINISH,
+	                        g_variant_new ("(o)", self->pv->prompt_path),
+	                        NULL, G_DBUS_CALL_FLAGS_NO_AUTO_START,
+	                        -1, NULL, on_prompt_close_async, g_object_ref (res));
+
+	g_object_unref (res);
+}
 
-	g_object_run_dispose (G_OBJECT (self));
+gboolean
+gcr_system_prompt_close_finish (GcrSystemPrompt *self,
+                                GAsyncResult *result,
+                                GError **error)
+{
+	g_return_val_if_fail (GCR_IS_SYSTEM_PROMPT (self), FALSE);
+	g_return_val_if_fail (error == NULL || *error == NULL, FALSE);
+
+	g_return_val_if_fail (g_simple_async_result_is_valid (result, G_OBJECT (self),
+	                      gcr_system_prompt_close_async), FALSE);
+
+	if (!g_simple_async_result_propagate_error (G_SIMPLE_ASYNC_RESULT (result), error))
+		return FALSE;
+
+	return TRUE;
 }
 
 static const GDBusErrorEntry SYSTEM_PROMPT_ERRORS[] = {
diff --git a/gcr/gcr-system-prompt.h b/gcr/gcr-system-prompt.h
index 19ffa1d..3fe2b33 100644
--- a/gcr/gcr-system-prompt.h
+++ b/gcr/gcr-system-prompt.h
@@ -39,7 +39,8 @@ G_BEGIN_DECLS
 typedef enum {
 	GCR_SYSTEM_PROMPT_IN_PROGRESS = 1,
 	GCR_SYSTEM_PROMPT_NOT_HAPPENING,
-	GCR_SYSTEM_PROMPT_FAILED
+	GCR_SYSTEM_PROMPT_FAILED,
+	GCR_SYSTEM_PROMPT_CLOSED
 } GcrSystemPromptError;
 
 #define GCR_SYSTEM_PROMPT_ERROR              (gcr_system_prompt_error_get_domain ())
@@ -167,7 +168,18 @@ gboolean             gcr_system_prompt_confirm                   (GcrSystemPromp
                                                                   GCancellable *cancellable,
                                                                   GError **error);
 
-void                 gcr_system_prompt_close                     (GcrSystemPrompt *self);
+gboolean             gcr_system_prompt_close                     (GcrSystemPrompt *self,
+                                                                  GCancellable *cancellable,
+                                                                  GError **error);
+
+void                 gcr_system_prompt_close_async               (GcrSystemPrompt *self,
+                                                                  GCancellable *cancellable,
+                                                                  GAsyncReadyCallback callback,
+                                                                  gpointer user_data);
+
+gboolean             gcr_system_prompt_close_finish              (GcrSystemPrompt *self,
+                                                                  GAsyncResult *result,
+                                                                  GError **error);
 
 G_END_DECLS
 
diff --git a/gcr/gcr-system-prompter.c b/gcr/gcr-system-prompter.c
index 7a60fc7..cf7eaa9 100644
--- a/gcr/gcr-system-prompter.c
+++ b/gcr/gcr-system-prompter.c
@@ -25,6 +25,8 @@
 
 #include "gcr-dbus-constants.h"
 #include "gcr-dbus-generated.h"
+#define DEBUG_FLAG GCR_DEBUG_PROMPT
+#include "gcr-debug.h"
 #include "gcr-internal.h"
 #include "gcr-library.h"
 #include "gcr-secret-exchange.h"
@@ -69,11 +71,11 @@ enum {
 };
 
 enum {
-	SHOW_PROMPT,
+	OPEN,
 	PROMPT_PASSWORD,
 	PROMPT_CONFIRM,
 	RESPONDED,
-	HIDE_PROMPT,
+	CLOSE,
 	LAST_SIGNAL
 };
 
@@ -88,7 +90,7 @@ struct _GcrSystemPrompterPrivate {
 	guint owner_watching_id;
 	GcrSecretExchange *exchange;
 	GDBusMethodInvocation *invocation;
-	gboolean shown;
+	gboolean opened;
 
 	/* Properties */
 	GHashTable *properties;
@@ -297,9 +299,10 @@ prompt_method_request_password (GcrSystemPrompter *self,
 
 	prompt_update_properties (self, properties);
 
-	if (!self->pv->shown) {
-		self->pv->shown = TRUE;
-		g_signal_emit (self, signals[SHOW_PROMPT], 0);
+	if (!self->pv->opened) {
+		self->pv->opened = TRUE;
+		_gcr_debug ("prompter opening prompt");
+		g_signal_emit (self, signals[OPEN], 0);
 	}
 
 	self->pv->invocation = invocation;
@@ -330,9 +333,10 @@ prompt_method_request_confirm (GcrSystemPrompter *self,
 
 	prompt_update_properties (self, properties);
 
-	if (!self->pv->shown) {
-		self->pv->shown = TRUE;
-		g_signal_emit (self, signals[SHOW_PROMPT], 0);
+	if (!self->pv->opened) {
+		self->pv->opened = TRUE;
+		_gcr_debug ("prompter opening prompt");
+		g_signal_emit (self, signals[OPEN], 0);
 	}
 
 	self->pv->invocation = invocation;
@@ -400,6 +404,7 @@ begin_prompting (GcrSystemPrompter *self,
 	g_assert (self->pv->prompt_path == NULL);
 
 	self->pv->prompt_path = g_strdup (GCR_DBUS_PROMPTER_OBJECT_PATH "/prompt0");
+	_gcr_debug ("prompter registering prompt: %s", self->pv->prompt_path);
 	self->pv->prompt_registered = g_dbus_connection_register_object (connection, self->pv->prompt_path,
 	                                                                 _gcr_prompter_prompt_interface_info (),
 	                                                                 &prompt_dbus_vtable, self, NULL, &error);
@@ -424,12 +429,14 @@ finish_prompting (GcrSystemPrompter *self)
 	prompt_clear_properties (self);
 
 	/* Tell the implementation to hide the display */
-	if (self->pv->shown) {
-		self->pv->shown = FALSE;
-		g_signal_emit (self, signals[HIDE_PROMPT], 0);
+	if (self->pv->opened) {
+		_gcr_debug ("prompter closing prompt");
+		self->pv->opened = FALSE;
+		g_signal_emit (self, signals[CLOSE], 0);
 	}
 
 	if (self->pv->owner_watching_id) {
+		_gcr_debug ("prompter stopping watch of client: %s", self->pv->owner_name);
 		g_bus_unwatch_name (self->pv->owner_watching_id);
 		self->pv->owner_watching_id = 0;
 	}
@@ -438,6 +445,7 @@ finish_prompting (GcrSystemPrompter *self)
 	self->pv->owner_name = NULL;
 
 	if (self->pv->prompt_registered) {
+		_gcr_debug ("prompter unregistering prompt: %s", self->pv->prompt_path);
 		if (!g_dbus_connection_unregister_object (self->pv->connection,
 		                                          self->pv->prompt_registered))
 			g_return_if_reached ();
@@ -530,6 +538,8 @@ gcr_system_prompter_dispose (GObject *obj)
 {
 	GcrSystemPrompter *self = GCR_SYSTEM_PROMPTER (obj);
 
+	_gcr_debug ("disposing prompter");
+
 	if (self->pv->invocation)
 		gcr_system_prompter_respond_cancelled (self);
 
@@ -546,6 +556,8 @@ gcr_system_prompter_finalize (GObject *obj)
 {
 	GcrSystemPrompter *self = GCR_SYSTEM_PROMPTER (obj);
 
+	_gcr_debug ("finalizing prompter");
+
 	g_hash_table_destroy (self->pv->properties);
 	g_queue_free (self->pv->properties_changed);
 
@@ -586,10 +598,10 @@ gcr_system_prompter_class_init (GcrSystemPrompterClass *klass)
 	gobject_class->dispose = gcr_system_prompter_dispose;
 	gobject_class->finalize = gcr_system_prompter_finalize;
 
-	klass->show_prompt = gcr_system_prompter_real_show_prompt;
+	klass->open = gcr_system_prompter_real_show_prompt;
 	klass->prompt_password= gcr_system_prompter_real_prompt_password;
 	klass->prompt_confirm = gcr_system_prompter_real_prompt_confirm;
-	klass->hide_prompt = gcr_system_prompter_real_hide_prompt;
+	klass->close = gcr_system_prompter_real_hide_prompt;
 
 	g_type_class_add_private (gobject_class, sizeof (GcrSystemPrompterPrivate));
 
@@ -629,9 +641,9 @@ gcr_system_prompter_class_init (GcrSystemPrompterClass *klass)
 	            g_param_spec_string ("caller-window", "Caller window", "Window id of caller",
 	                                 "", G_PARAM_READABLE));
 
-	signals[SHOW_PROMPT] = g_signal_new ("show-prompt", GCR_TYPE_SYSTEM_PROMPTER, G_SIGNAL_RUN_LAST,
-	                                     G_STRUCT_OFFSET (GcrSystemPrompterClass, show_prompt),
-	                                     NULL, NULL, NULL, G_TYPE_NONE, 0);
+	signals[OPEN] = g_signal_new ("open", GCR_TYPE_SYSTEM_PROMPTER, G_SIGNAL_RUN_LAST,
+	                              G_STRUCT_OFFSET (GcrSystemPrompterClass, open),
+	                              NULL, NULL, NULL, G_TYPE_NONE, 0);
 
 	signals[PROMPT_PASSWORD] = g_signal_new ("prompt-password", GCR_TYPE_SYSTEM_PROMPTER, G_SIGNAL_RUN_LAST,
 	                                         G_STRUCT_OFFSET (GcrSystemPrompterClass, prompt_password),
@@ -647,9 +659,9 @@ gcr_system_prompter_class_init (GcrSystemPrompterClass *klass)
 	                                   G_STRUCT_OFFSET (GcrSystemPrompterClass, responded),
 	                                   NULL, NULL, NULL, G_TYPE_NONE, 0);
 
-	signals[HIDE_PROMPT] = g_signal_new ("hide-prompt", GCR_TYPE_SYSTEM_PROMPTER, G_SIGNAL_RUN_LAST,
-	                                     G_STRUCT_OFFSET (GcrSystemPrompterClass, hide_prompt),
-	                                     NULL, NULL, NULL, G_TYPE_NONE, 0);
+	signals[CLOSE] = g_signal_new ("close", GCR_TYPE_SYSTEM_PROMPTER, G_SIGNAL_RUN_LAST,
+	                               G_STRUCT_OFFSET (GcrSystemPrompterClass, close),
+	                               NULL, NULL, NULL, G_TYPE_NONE, 0);
 }
 
 static void
@@ -713,6 +725,7 @@ prompter_method_begin_prompting (GcrSystemPrompter *self,
 	g_return_if_fail (self->pv->owner_name != NULL);
 
 	connection = g_dbus_method_invocation_get_connection (invocation);
+	_gcr_debug ("prompter starting watch of dbus client: %s", self->pv->owner_name);
 	self->pv->owner_watching_id = g_bus_watch_name_on_connection (connection,
 	                                                              self->pv->owner_name,
 	                                                              G_BUS_NAME_WATCHER_FLAGS_NONE,
@@ -730,6 +743,7 @@ prompter_method_finish_prompting (GcrSystemPrompter *self,
                                   const gchar *prompt)
 {
 	if (g_strcmp0 (prompt, self->pv->prompt_path) != 0) {
+		_gcr_debug ("caller passed invalid prompt: %s != %s", prompt, self->pv->prompt_path);
 		g_dbus_method_invocation_return_error_literal (invocation,
 		                                               G_DBUS_ERROR,
 		                                               G_DBUS_ERROR_INVALID_ARGS,
@@ -738,6 +752,7 @@ prompter_method_finish_prompting (GcrSystemPrompter *self,
 	}
 
 	if (self->pv->owner_name == NULL) {
+		_gcr_debug ("prompting is not in progress");
 		g_dbus_method_invocation_return_error_literal (invocation,
 		                                               GCR_SYSTEM_PROMPT_ERROR,
 		                                               GCR_SYSTEM_PROMPT_NOT_HAPPENING,
@@ -745,6 +760,8 @@ prompter_method_finish_prompting (GcrSystemPrompter *self,
 		return;
 	}
 
+	_gcr_debug ("finishing prompting owned by caller %s", self->pv->owner_name);
+
 	/* Close a prompt that's prompting */
 	if (self->pv->invocation != NULL)
 		gcr_system_prompter_respond_cancelled (self);
@@ -800,6 +817,8 @@ gcr_system_prompter_register (GcrSystemPrompter *self,
 	g_return_if_fail (self->pv->prompter_registered == 0);
 	g_return_if_fail (self->pv->connection == NULL);
 
+	_gcr_debug ("registering prompter");
+
 	self->pv->connection = connection;
 	g_object_add_weak_pointer (G_OBJECT (connection), (gpointer *)&self->pv->connection);
 
@@ -825,6 +844,8 @@ gcr_system_prompter_unregister (GcrSystemPrompter *self,
 	g_return_if_fail (self->pv->prompter_registered != 0);
 	g_return_if_fail (self->pv->connection == connection);
 
+	_gcr_debug ("unregistering prompter");
+
 	if (self->pv->invocation)
 		gcr_system_prompter_respond_cancelled (self);
 
@@ -1036,6 +1057,8 @@ gcr_system_prompter_respond_cancelled (GcrSystemPrompter *self)
 	/* Don't send back any changed properties on cancel */
 	properties = g_variant_new_array (G_VARIANT_TYPE ("(ssv)"), NULL, 0);
 
+	_gcr_debug ("responding to with cancelled");
+
 	method = g_dbus_method_invocation_get_method_name (invocation);
 	if (method && g_str_equal (method, GCR_DBUS_PROMPT_METHOD_PASSWORD))
 		g_dbus_method_invocation_return_value (invocation,
@@ -1076,11 +1099,13 @@ gcr_system_prompter_respond_with_password (GcrSystemPrompter *self,
 	invocation = self->pv->invocation;
 	self->pv->invocation = NULL;
 
+	method = g_dbus_method_invocation_get_method_name (invocation);
+	g_return_if_fail (method != NULL && g_str_equal (method, GCR_DBUS_PROMPT_METHOD_PASSWORD));
+
 	/* Send back all the properties before we respond */
 	properties = build_changed_properties (self);
 
-	method = g_dbus_method_invocation_get_method_name (invocation);
-	g_return_if_fail (method != NULL && g_str_equal (method, GCR_DBUS_PROMPT_METHOD_PASSWORD));
+	_gcr_debug ("responding to prompt with password");
 
 	exchange = gcr_secret_exchange_send (self->pv->exchange, password, -1);
 	g_dbus_method_invocation_return_value (invocation, g_variant_new ("(@a(ssv)s)",
@@ -1115,6 +1140,9 @@ gcr_system_prompter_respond_confirmed (GcrSystemPrompter *self)
 
 	method = g_dbus_method_invocation_get_method_name (invocation);
 	g_return_if_fail (method != NULL && g_str_equal (method, GCR_DBUS_PROMPT_METHOD_CONFIRM));
+
+	_gcr_debug ("responding to prompt with confirm");
+
 	g_dbus_method_invocation_return_value (invocation, g_variant_new ("(@a(ssv)b)",
 	                                                                  properties, TRUE));
 
diff --git a/gcr/gcr-system-prompter.h b/gcr/gcr-system-prompter.h
index ad84ecb..b697473 100644
--- a/gcr/gcr-system-prompter.h
+++ b/gcr/gcr-system-prompter.h
@@ -53,7 +53,7 @@ struct _GcrSystemPrompter {
 struct _GcrSystemPrompterClass {
 	GObjectClass parent_class;
 
-	void         (*show_prompt)             (GcrSystemPrompter *self);
+	void         (*open)                    (GcrSystemPrompter *self);
 
 	gboolean     (*prompt_password)         (GcrSystemPrompter *self);
 
@@ -61,7 +61,7 @@ struct _GcrSystemPrompterClass {
 
 	void         (*responded)               (GcrSystemPrompter *self);
 
-	void         (*hide_prompt)             (GcrSystemPrompter *self);
+	void         (*close)                   (GcrSystemPrompter *self);
 };
 
 GType                gcr_system_prompter_get_type                  (void) G_GNUC_CONST;
diff --git a/gcr/tests/frob-system-prompt.c b/gcr/tests/frob-system-prompt.c
new file mode 100644
index 0000000..ef01139
--- /dev/null
+++ b/gcr/tests/frob-system-prompt.c
@@ -0,0 +1,106 @@
+/*
+ * gnome-keyring
+ *
+ * Copyright (C) 2011 Collabora Ltd.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as
+ * published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This program 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
+ * 02111-1307, USA.
+ *
+ * Author: Stef Walter <stefw collabora co uk>
+ */
+
+#include "config.h"
+
+#include "gcr/gcr.h"
+
+#include <gtk/gtk.h>
+#include <gdk/gdkx.h>
+
+#include <unistd.h>
+#include <string.h>
+#include <errno.h>
+
+static void
+on_prompt_clicked (GtkToolButton *button,
+                   gpointer user_data)
+{
+	GcrSystemPrompt *prompt;
+	GError *error = NULL;
+	const gchar *password;
+	GtkWidget *parent = user_data;
+	gchar *caller_id;
+
+	prompt = gcr_system_prompt_open (-1, NULL, &error);
+	if (error != NULL) {
+		g_warning ("couldn't open prompt: %s", error->message);
+		g_error_free (error);
+		return;
+	}
+
+	gcr_system_prompt_set_title (prompt, "This is the title");
+	gcr_system_prompt_set_message (prompt, "This is the message");
+	gcr_system_prompt_set_description (prompt, "This is the description");
+
+	caller_id = g_strdup_printf ("%lu", (gulong)GDK_WINDOW_XID (gtk_widget_get_window (parent)));
+	gcr_system_prompt_set_caller_window (prompt, caller_id);
+	g_free (caller_id);
+
+	password = gcr_system_prompt_password (prompt, NULL, &error);
+	if (error != NULL) {
+		g_warning ("couldn't prompt for password: %s", error->message);
+		g_error_free (error);
+		g_object_unref (prompt);
+		return;
+	}
+
+	g_print ("password: %s\n", password);
+	g_object_unref (prompt);
+}
+
+static gboolean
+on_window_delete (GtkWidget *widget,
+                  GdkEvent *event,
+                  gpointer user_data)
+{
+	gtk_main_quit ();
+	return FALSE;
+}
+
+int
+main (int argc, char *argv[])
+{
+	GtkWidget *window;
+	GtkToolbar *toolbar;
+	GtkToolItem *item;
+
+	gtk_init (&argc, &argv);
+
+	window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
+	g_signal_connect (window, "delete-event", G_CALLBACK (on_window_delete), NULL);
+
+	toolbar = GTK_TOOLBAR (gtk_toolbar_new ());
+	gtk_toolbar_set_style (toolbar, GTK_TOOLBAR_TEXT);
+	item = gtk_tool_button_new (NULL, "Prompt");
+	g_signal_connect (item, "clicked", G_CALLBACK (on_prompt_clicked), window);
+	gtk_toolbar_insert (toolbar, item, 0);
+	gtk_container_add (GTK_CONTAINER (window), GTK_WIDGET (toolbar));
+
+	gtk_window_set_default_size (GTK_WINDOW (window), 400, 80);
+	gtk_widget_show_all (window);
+
+	gtk_main ();
+
+	return 0;
+}
diff --git a/gcr/tests/test-system-prompt.c b/gcr/tests/test-system-prompt.c
new file mode 100644
index 0000000..aec1ce6
--- /dev/null
+++ b/gcr/tests/test-system-prompt.c
@@ -0,0 +1,409 @@
+/* -*- Mode: C; indent-tabs-mode: t; c-basic-offset: 8; tab-width: 8 -*- */
+/*
+   Copyright (C) 2011 Collabora Ltd
+
+   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 collabora co uk>
+*/
+
+#include "config.h"
+
+#include "gcr/gcr-base.h"
+#include "gcr/gcr-mock-prompter.h"
+
+#include "egg/egg-testing.h"
+
+#include <glib.h>
+
+typedef struct {
+	const gchar *prompter_name;
+} Test;
+
+static void
+setup (Test *test,
+       gconstpointer unused)
+{
+	test->prompter_name = gcr_mock_prompter_start ();
+}
+
+static void
+teardown (Test *test,
+          gconstpointer unused)
+{
+	gcr_mock_prompter_stop ();
+}
+
+static void
+test_prompt_password (Test *test,
+                      gconstpointer unused)
+{
+	GcrSystemPrompt *prompt;
+	GError *error = NULL;
+	const gchar *password;
+
+	gcr_mock_prompter_expect_password_ok ("booo", NULL);
+
+	prompt = gcr_system_prompt_open_for_prompter (test->prompter_name, 0, NULL, &error);
+	g_assert_no_error (error);
+	g_assert (GCR_IS_SYSTEM_PROMPT (prompt));
+
+	password = gcr_system_prompt_password (prompt, NULL, &error);
+	g_assert_no_error (error);
+	g_assert_cmpstr (password, ==, "booo");
+
+	g_object_unref (prompt);
+	g_assert (!G_IS_OBJECT (prompt));
+}
+
+static void
+test_password_in_exchange (Test *test,
+                           gconstpointer unused)
+{
+	GcrSystemPrompt *prompt;
+	GError *error = NULL;
+	GcrSecretExchange *exchange;
+
+	gcr_mock_prompter_expect_password_ok ("booo", NULL);
+
+	prompt = gcr_system_prompt_open_for_prompter (test->prompter_name, 0, NULL, &error);
+	g_assert_no_error (error);
+	g_assert (GCR_IS_SYSTEM_PROMPT (prompt));
+
+	gcr_system_prompt_password (prompt, NULL, &error);
+	g_assert_no_error (error);
+
+	g_object_get (prompt, "secret-exchange", &exchange, NULL);
+	g_assert (GCR_IS_SECRET_EXCHANGE (exchange));
+	g_assert_cmpstr (gcr_secret_exchange_get_secret (exchange, NULL), ==, "booo");
+
+	g_object_unref (exchange);
+	g_object_unref (prompt);
+	g_assert (!G_IS_OBJECT (prompt));
+}
+
+static void
+on_async_result (GObject *source,
+                 GAsyncResult *result,
+                 gpointer user_data)
+{
+	GAsyncResult **ret = user_data;
+	*ret = g_object_ref (result);
+	egg_test_wait_stop ();
+}
+
+static void
+test_async_password (Test *test,
+                     gconstpointer unused)
+{
+	GAsyncResult *result = NULL;
+	GcrSystemPrompt *prompt;
+	GError *error = NULL;
+	const gchar *password;
+
+	gcr_mock_prompter_expect_password_ok ("booo", NULL);
+
+	gcr_system_prompt_open_for_prompter_async (test->prompter_name, 0, NULL,
+	                                           on_async_result, &result);
+	g_assert (result == NULL);
+	egg_test_wait ();
+
+	g_assert (result != NULL);
+	prompt = gcr_system_prompt_open_finish (result, &error);
+	g_assert_no_error (error);
+	g_assert (GCR_IS_SYSTEM_PROMPT (prompt));
+	g_clear_object (&result);
+
+	gcr_system_prompt_password_async (prompt, NULL,
+	                                  on_async_result, &result);
+	g_assert (result == NULL);
+	egg_test_wait ();
+
+	password = gcr_system_prompt_password_finish (prompt, result, &error);
+	g_assert_no_error (error);
+	g_assert_cmpstr (password, ==, "booo");
+	g_clear_object (&result);
+
+	g_object_unref (prompt);
+}
+
+static void
+test_prompt_confirm (Test *test,
+                     gconstpointer unused)
+{
+	GcrSystemPrompt *prompt;
+	GError *error = NULL;
+	gboolean ret;
+
+	gcr_mock_prompter_expect_confirm_ok (NULL);
+
+	prompt = gcr_system_prompt_open_for_prompter (test->prompter_name, 0, NULL, &error);
+	g_assert_no_error (error);
+	g_assert (GCR_IS_SYSTEM_PROMPT (prompt));
+
+	ret = gcr_system_prompt_confirm (prompt, NULL, &error);
+	g_assert_no_error (error);
+	g_assert (ret == TRUE);
+
+	g_object_unref (prompt);
+	g_assert (!G_IS_OBJECT (prompt));
+}
+
+static void
+test_async_confirm (Test *test,
+                    gconstpointer unused)
+{
+	GAsyncResult *result = NULL;
+	GcrSystemPrompt *prompt;
+	GError *error = NULL;
+	gboolean confirm;
+
+	gcr_mock_prompter_expect_confirm_ok (NULL);
+
+	gcr_system_prompt_open_for_prompter_async (test->prompter_name, 0, NULL,
+	                                           on_async_result, &result);
+	g_assert (result == NULL);
+	egg_test_wait ();
+
+	g_assert (result != NULL);
+	prompt = gcr_system_prompt_open_finish (result, &error);
+	g_assert_no_error (error);
+	g_assert (GCR_IS_SYSTEM_PROMPT (prompt));
+	g_clear_object (&result);
+
+	gcr_system_prompt_confirm_async (prompt, NULL,
+	                                 on_async_result, &result);
+	g_assert (result == NULL);
+	egg_test_wait ();
+
+	confirm = gcr_system_prompt_confirm_finish (prompt, result, &error);
+	g_assert_no_error (error);
+	g_assert (confirm == TRUE);
+	g_clear_object (&result);
+
+	g_object_unref (prompt);
+	g_assert (!G_IS_OBJECT (prompt));
+}
+
+static void
+test_cancel_password (Test *test,
+                      gconstpointer unused)
+{
+	GcrSystemPrompt *prompt;
+	GError *error = NULL;
+	const gchar *password;
+
+	gcr_mock_prompter_expect_password_cancel ();
+
+	prompt = gcr_system_prompt_open_for_prompter (test->prompter_name, 0, NULL, &error);
+	g_assert_no_error (error);
+	g_assert (GCR_IS_SYSTEM_PROMPT (prompt));
+
+	password = gcr_system_prompt_password (prompt, NULL, &error);
+	g_assert_no_error (error);
+	g_assert_cmpstr (password, ==, NULL);
+
+	g_object_unref (prompt);
+	g_assert (!G_IS_OBJECT (prompt));
+}
+
+static void
+test_cancel_confirm (Test *test,
+                     gconstpointer unused)
+{
+	GcrSystemPrompt *prompt;
+	GError *error = NULL;
+	gboolean ret;
+
+	gcr_mock_prompter_expect_confirm_cancel ();
+
+	prompt = gcr_system_prompt_open_for_prompter (test->prompter_name, 0, NULL, &error);
+	g_assert_no_error (error);
+	g_assert (GCR_IS_SYSTEM_PROMPT (prompt));
+
+	ret = gcr_system_prompt_confirm (prompt, NULL, &error);
+	g_assert_no_error (error);
+	g_assert (ret == FALSE);
+
+	g_object_unref (prompt);
+	g_assert (!G_IS_OBJECT (prompt));
+}
+
+static void
+test_prompt_properties (Test *test,
+                        gconstpointer unused)
+{
+	GcrSystemPrompt *prompt;
+	GError *error = NULL;
+	gboolean ret;
+
+	gcr_mock_prompter_expect_confirm_ok ("title", "My Title",
+	                                     "description", "My Description",
+	                                     "warning", "My Warning",
+	                                     "message", "My Message",
+	                                     "caller-window", "01010",
+	                                     "choice-label", "My Choice",
+	                                     "choice-chosen", TRUE,
+	                                     "password-new", TRUE,
+	                                     "password-strength", 2,
+	                                     NULL);
+
+	prompt = gcr_system_prompt_open_for_prompter (test->prompter_name, 0, NULL, &error);
+	g_assert_no_error (error);
+	g_assert (GCR_IS_SYSTEM_PROMPT (prompt));
+
+	g_object_set (prompt,
+	              "title", "Other Title",
+	              "choice-label", "Other Choice",
+	              "description", "Other Description",
+	              "message", "Other Message",
+	              "caller-window", "01012",
+	              "warning", "Other Warning",
+	              "password-new", FALSE,
+	              "choice-chosen", TRUE,
+	              NULL);
+
+	g_assert_cmpstr (gcr_system_prompt_get_title (prompt), ==, "Other Title");
+	g_assert_cmpstr (gcr_system_prompt_get_choice_label (prompt), ==, "Other Choice");
+	g_assert_cmpstr (gcr_system_prompt_get_description (prompt), ==, "Other Description");
+	g_assert_cmpstr (gcr_system_prompt_get_message (prompt), ==, "Other Message");
+	g_assert_cmpstr (gcr_system_prompt_get_caller_window (prompt), ==, "01012");
+	g_assert_cmpstr (gcr_system_prompt_get_warning (prompt), ==, "Other Warning");
+	g_assert (gcr_system_prompt_get_password_new (prompt) == FALSE);
+	g_assert (gcr_system_prompt_get_choice_chosen (prompt) == TRUE);
+
+	gcr_system_prompt_set_title (prompt, "My Title");
+	gcr_system_prompt_set_choice_label (prompt, "My Choice");
+	gcr_system_prompt_set_description (prompt, "My Description");
+	gcr_system_prompt_set_message (prompt, "My Message");
+	gcr_system_prompt_set_caller_window (prompt, "01010");
+	gcr_system_prompt_set_warning (prompt, "My Warning");
+	gcr_system_prompt_set_password_new (prompt, TRUE);
+	gcr_system_prompt_set_choice_chosen (prompt, FALSE);
+
+	ret = gcr_system_prompt_confirm (prompt, NULL, &error);
+	g_assert_no_error (error);
+	g_assert (ret == TRUE);
+
+	g_assert (gcr_system_prompt_get_choice_chosen (prompt) == TRUE);
+	g_assert_cmpint (gcr_system_prompt_get_password_strength (prompt), ==, 2);
+
+	g_object_unref (prompt);
+	g_assert (!G_IS_OBJECT (prompt));
+}
+
+static void
+test_prompt_close (Test *test,
+                   gconstpointer unused)
+{
+	GcrSystemPrompt *prompt;
+	GcrSystemPrompt *prompt2;
+	GError *error = NULL;
+	gboolean showing;
+	gboolean ret;
+
+	gcr_mock_prompter_expect_confirm_ok (NULL);
+
+	prompt = gcr_system_prompt_open_for_prompter (test->prompter_name, 0, NULL, &error);
+	g_assert_no_error (error);
+	g_assert (GCR_IS_SYSTEM_PROMPT (prompt));
+
+	prompt2 = gcr_system_prompt_open_for_prompter (test->prompter_name, 0, NULL, &error);
+	g_assert_error (error, GCR_SYSTEM_PROMPT_ERROR, GCR_SYSTEM_PROMPT_IN_PROGRESS);
+	g_clear_error (&error);
+	g_assert (prompt2 == NULL);
+
+	ret = gcr_system_prompt_confirm (prompt, NULL, &error);
+	g_assert_no_error (error);
+	g_assert (ret == TRUE);
+
+	prompt2 = gcr_system_prompt_open_for_prompter (test->prompter_name, 0, NULL, &error);
+	g_assert_error (error, GCR_SYSTEM_PROMPT_ERROR, GCR_SYSTEM_PROMPT_IN_PROGRESS);
+	g_clear_error (&error);
+	g_assert (prompt2 == NULL);
+
+	showing = gcr_mock_prompter_get_showing ();
+	g_assert (showing == TRUE);
+
+	gcr_system_prompt_close (prompt, NULL, &error);
+	g_assert_no_error (error);
+
+	showing = gcr_mock_prompter_get_showing ();
+	g_assert (showing == FALSE);
+
+	prompt2 = gcr_system_prompt_open_for_prompter (test->prompter_name, 0, NULL, &error);
+	g_assert_no_error (error);
+	g_assert (GCR_IS_SYSTEM_PROMPT (prompt2));
+
+	g_object_unref (prompt);
+	g_assert (!G_IS_OBJECT (prompt));
+
+	g_object_unref (prompt2);
+	g_assert (!G_IS_OBJECT (prompt2));
+}
+
+static void
+test_finish_cancels (Test *test,
+                     gconstpointer unused)
+{
+	GcrSystemPrompt *prompt;
+	GError *error = NULL;
+	const gchar *password = NULL;
+	GAsyncResult *result = NULL;
+
+	gcr_mock_prompter_set_delay_msec (3000);
+	gcr_mock_prompter_expect_password_ok ("booo", NULL);
+
+	prompt = gcr_system_prompt_open_for_prompter (test->prompter_name, 0, NULL, &error);
+	g_assert_no_error (error);
+	g_assert (GCR_IS_SYSTEM_PROMPT (prompt));
+
+	gcr_system_prompt_password_async (prompt, NULL, on_async_result, &result);
+
+	gcr_system_prompt_close (prompt, NULL, &error);
+	g_assert_no_error (error);
+
+	egg_test_wait ();
+
+	password = gcr_system_prompt_password_finish (prompt, result, &error);
+	g_assert_no_error (error);
+	g_assert (password == NULL);
+	g_clear_object (&result);
+
+	g_object_unref (prompt);
+	g_assert (!G_IS_OBJECT (prompt));
+}
+
+int
+main (int argc, char **argv)
+{
+	g_type_init ();
+	g_test_init (&argc, &argv, NULL);
+	g_set_prgname ("test-system-prompt");
+
+	g_test_add ("/gcr/system-prompt/password", Test, NULL, setup, test_prompt_password, teardown);
+	g_test_add ("/gcr/system-prompt/password-async", Test, NULL, setup, test_async_password, teardown);
+	g_test_add ("/gcr/system-prompt/password-cancel", Test, NULL, setup, test_cancel_password, teardown);
+	g_test_add ("/gcr/system-prompt/password-in-exchange", Test, NULL, setup, test_password_in_exchange, teardown);
+	g_test_add ("/gcr/system-prompt/confirm", Test, NULL, setup, test_prompt_confirm, teardown);
+	g_test_add ("/gcr/system-prompt/confirm-async", Test, NULL, setup, test_async_confirm, teardown);
+	g_test_add ("/gcr/system-prompt/confirm-cancel", Test, NULL, setup, test_cancel_confirm, teardown);
+	g_test_add ("/gcr/system-prompt/properties", Test, NULL, setup, test_prompt_properties, teardown);
+	g_test_add ("/gcr/system-prompt/close", Test, NULL, setup, test_prompt_close, teardown);
+	g_test_add ("/gcr/system-prompt/finish-cancel", Test, NULL, setup, test_finish_cancels, teardown);
+
+	return egg_tests_run_with_loop ();
+}



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