[tracker/wip/removable-device-completed: 9/11] tests: Add GIO module to generate fake removable devices



commit 19f845b7dab450aee6d2b19153eec5b832b6ca42
Author: Sam Thursfield <sam thursfield codethink co uk>
Date:   Mon May 28 12:03:56 2012 +0900

    tests: Add GIO module to generate fake removable devices
    
    tracker-test-volume-monitor is a GIO module that can be loaded via
    GIO_EXTRA_MODULES in the environment and will expose fake removable
    devices.
    
    tracker-test-mount-service is a D-Bus service that controls all of the
    test volume monitors within a D-Bus session. This allows the
    functional tests to simulate removable devices without needing any
    hooks inside the actual Tracker processes.

 tests/common/Makefile.am                      |   22 ++-
 tests/common/tracker-test-mount-service.vala  |  129 ++++++++++
 tests/common/tracker-test-volume-monitor.vala |  316 +++++++++++++++++++++++++
 utils/tracker-sandbox                         |    7 +
 4 files changed, 473 insertions(+), 1 deletions(-)
---
diff --git a/tests/common/Makefile.am b/tests/common/Makefile.am
index acca798..11b46ab 100644
--- a/tests/common/Makefile.am
+++ b/tests/common/Makefile.am
@@ -1,12 +1,27 @@
 include $(top_srcdir)/Makefile.decl
 
-noinst_LTLIBRARIES = libtracker-testcommon.la
+# Don't install the test volume monitor into gio/modules or it will
+# be loaded system-wide ... would be better to not install it at all,
+# but it's used by the functional tests which operate on an installed
+# Tracker.
+moduledir = $(libdir)/tracker
+
+noinst_LTLIBRARIES = \
+	libtracker-testcommon.la
+
+module_LTLIBRARIES = \
+	libtracker-test-volume-monitor.la
+
+libexec_PROGRAMS = \
+	tracker-test-mounter-service
 
 AM_CPPFLAGS =                                          \
 	$(BUILD)                                       \
 	-DTEST_TEXT=\""$(top_srcdir)"/tests/libtracker-common/non-utf8.txt\" \
 	$(LIBTRACKER_COMMON_CFLAGS)
 
+AM_VALAFLAGS = --pkg=gio-2.0 --pkg=gmodule-2.0 -g
+
 LDADD =                                                \
 	$(BUILD_LIBS)                                  \
 	$(LIBTRACKER_COMMON_LIBS)
@@ -15,3 +30,8 @@ libtracker_testcommon_la_SOURCES =                     \
 	tracker-test-helpers.c                         \
 	tracker-test-helpers.h
 
+libtracker_test_volume_monitor_la_SOURCES =            \
+	tracker-test-volume-monitor.vala
+
+tracker_test_mounter_service_SOURCES =                 \
+	tracker-test-mount-service.vala
diff --git a/tests/common/tracker-test-mount-service.vala b/tests/common/tracker-test-mount-service.vala
new file mode 100644
index 0000000..30613ed
--- /dev/null
+++ b/tests/common/tracker-test-mount-service.vala
@@ -0,0 +1,129 @@
+/*
+ * Copyright (C) 2012, Codethink Ltd <sam thursfield codethink co uk>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * 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 General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+ * 02110-1301, USA.
+ */
+
+/* A slightly overengineed method of implementing test mounts. It might be
+ * nicer if GVfs would support this directly, see:
+ * https://bugzilla.gnome.org/show_bug.cgi?id=659739
+ *
+ * Tests can run this daemon and use it to control the
+ * tracker-test-volume-monitor GIO module, creating fake mounts for all of the
+ * Tracker processes.
+ */
+
+using GLib;
+
+struct Tracker.TestMountInfo {
+	public string root_path;
+	public uint id;
+}
+
+[DBus (name="org.freedesktop.Tracker1.TestMounter")]
+public class Tracker.TestMountService {
+	List<TestMountInfo?> mount_list;
+	uint id_counter;
+
+	internal void on_bus_acquired (DBusConnection connection,
+	                               string         name) {
+		try {
+			connection.register_object ("/org/freedesktop/Tracker1/TestMounter", this);
+		}
+		catch (IOError e) {
+			stderr.printf ("tracker-test-volume-monitor: Error exporting on bus: %s\n", e.message);
+		}
+	}
+
+	internal void on_name_acquired (DBusConnection connection,
+	                                string         name) {
+	}
+
+	internal void on_name_lost (DBusConnection connection,
+	                            string         name) {
+		stderr.printf ("tracker-test-volume-monitor: Unable to own bus name\n");
+	}
+
+	public Variant list_mounts () {
+		var result = new VariantBuilder ((VariantType) "a(su)");
+
+		foreach (var mount_info in this.mount_list)
+			result.add ("(su)", mount_info.root_path, mount_info.id);
+
+		return result.end();
+	}
+
+	private unowned List<TestMountInfo?>? find_mount_info_node (string root_path) {
+		for (unowned List<TestMountInfo?> l = this.mount_list; l != null; l = l.next) {
+			if (l.data.root_path == root_path)
+				return l;
+		}
+
+		return null;
+	}
+
+	public void mount (string root_path)
+	                  throws GLib.IOError {
+		unowned List<TestMountInfo?> node = this.find_mount_info_node (root_path);
+
+		if (node != null)
+			throw new IOError.ALREADY_MOUNTED ("Unable to mount %s: already mounted", root_path);
+
+		var mount_info = TestMountInfo ();
+
+		mount_info.root_path = root_path;
+		mount_info.id = this.id_counter ++;
+
+		this.mount_list.append (mount_info);
+
+		this.mount_added (mount_info.root_path, mount_info.id);
+	}
+
+	public void unmount (string root_path)
+	                    throws IOError {
+		unowned List<TestMountInfo?> node = this.find_mount_info_node (root_path);
+
+		if (node == null)
+			throw new IOError.NOT_MOUNTED ("Unable to unmount %s: not mounted", root_path);
+
+		var mount_info = node.data;
+
+		this.mount_list.remove_link (node);
+
+		this.mount_removed (mount_info.root_path);
+	}
+
+	public signal void mount_added (string root_path,
+	                                uint   id);
+
+	public signal void mount_removed (string root_path);
+}
+
+public int main (string args[]) {
+	var loop = new MainLoop ();
+	var service = new Tracker.TestMountService ();
+
+	Bus.own_name (BusType.SESSION,
+	              "org.freedesktop.Tracker1.TestMounter",
+	              BusNameOwnerFlags.NONE,
+	              service.on_bus_acquired,
+	              service.on_name_acquired,
+	              service.on_name_lost);
+
+	loop.run ();
+
+	return 0;
+}
diff --git a/tests/common/tracker-test-volume-monitor.vala b/tests/common/tracker-test-volume-monitor.vala
new file mode 100644
index 0000000..ee8b470
--- /dev/null
+++ b/tests/common/tracker-test-volume-monitor.vala
@@ -0,0 +1,316 @@
+/*
+ * Copyright (C) 2012, Codethink Ltd <sam thursfield codethink co uk>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * 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 General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+ * 02110-1301, USA.
+ */
+
+/* WARNING: due to issues in gio-2.0.vapi, this file is really hard to
+ * compile with Vala. See https://bugzilla.gnome.org/show_bug.cgi?id=677073
+ * for more information. Use either 0.15.0 or >= 0.17.1
+ */
+
+private class Tracker.TestMount: GLib.Mount, GLib.Object {
+	internal File root;
+	internal string root_path;
+	internal uint id;
+
+	public TestMount (string root_path,
+	                  uint   id) {
+		this.root_path = root_path;
+		this.id = id;
+	}
+
+	public File get_root () {
+		if (root == null)
+			// Can't create a GLib.File in the constructor due to locking in GIO
+			this.root = File.new_for_path (root_path);
+
+		return root;
+	}
+
+	public Icon get_icon () {
+		return null;
+	}
+
+	public string get_name () {
+		return "Test Mount %u".printf(id);
+	}
+
+	public File get_default_location () {
+		return this.get_root ();
+	}
+
+	public string get_uuid () {
+		return "FFFF-F%03u".printf(id);
+	}
+
+	public Volume get_volume () {
+		return null;
+	}
+
+	public Drive get_drive () {
+		return null;
+	}
+
+	public bool can_unmount () {
+		return true;
+	}
+
+	public bool can_eject () {
+		return false;
+	}
+
+	public async bool eject (GLib.MountUnmountFlags flags,
+	                         GLib.Cancellable? cancellable)
+	                        throws GLib.Error {
+		return false;
+	}
+
+	public async bool eject_with_operation (GLib.MountUnmountFlags flags,
+	                                        GLib.MountOperation? mount_operation,
+	                                        GLib.Cancellable? cancellable)
+	                                       throws GLib.Error {
+		return false;
+	}
+
+
+	public string[] guess_content_type_sync (bool         force_rescan,
+	                                         Cancellable? cancellable)
+	                                        throws GLib.Error {
+		return new string[1];
+	}
+
+	public async string[] guess_content_type (bool         force_rescan,
+	                                          Cancellable? cancellable)
+	                                         throws GLib.Error {
+		return guess_content_type_sync (force_rescan, cancellable);
+	}
+
+	public async bool remount (GLib.MountMountFlags flags,
+	                           GLib.MountOperation? mount_operation,
+	                           GLib.Cancellable? cancellable)
+	                           throws GLib.Error {
+		return false;
+	}
+
+	public async bool unmount (MountUnmountFlags  flags,
+	                           Cancellable?       cancellable)
+	                           throws GLib.Error {
+		return yield this.unmount_with_operation (flags, null, cancellable);
+	}
+
+	public async bool unmount_with_operation (MountUnmountFlags   flags,
+	                                          MountOperation?     operation,
+	                                          Cancellable?        cancellable)
+	                                         throws GLib.Error {
+		return false;
+	}
+
+#if GLIB_2_32
+	public unowned string get_sort_key () {
+		return null;
+	}
+#endif
+}
+
+public class Tracker.TestVolumeMonitor: GLib.VolumeMonitor {
+	List<Mount> mount_list;
+	uint dbus_mount_added_id;
+	uint dbus_mount_removed_id;
+
+	construct {
+		// GObject construction is required because GUnionVolumeMonitor has to
+		// use g_object_new() to create an instance.
+
+		this.mount_list = null;
+
+		Bus.watch_name (BusType.SESSION,
+		                "org.freedesktop.Tracker1.TestMounter",
+		                BusNameWatcherFlags.NONE,
+		                on_test_mount_service_appeared,
+		                on_test_mount_service_vanished);
+	}
+
+	void on_test_mount_service_appeared (DBusConnection connection,
+	                                     string         name,
+	                                     string         name_owner) {
+		dbus_mount_added_id = connection.signal_subscribe
+		    (name,
+		     "org.freedesktop.Tracker1.TestMounter",
+		     "MountAdded",
+		     "/org/freedesktop/Tracker1/TestMounter",
+		     null,
+		     DBusSignalFlags.NONE,
+		     dbus_mount_added_cb);
+
+		dbus_mount_removed_id = connection.signal_subscribe
+		    (name,
+		     "org.freedesktop.Tracker1.TestMounter",
+		     "MountRemoved",
+		     "/org/freedesktop/Tracker1/TestMounter",
+		     null,
+		     DBusSignalFlags.NONE,
+		     dbus_mount_removed_cb);
+
+		connection.call.begin (name,
+		                       "/org/freedesktop/Tracker1/TestMounter",
+		                       "org.freedesktop.Tracker1.TestMounter",
+		                       "ListMounts",
+		                       null, null, DBusCallFlags.NONE, -1, null,
+		                       (s, r) => {
+			Variant reply;
+ 
+			try {
+				reply = connection.call.end (r);
+			}
+			catch (Error e) {
+				warning ("Call to org.freedesktop.Tracker1.TestMounter.ListMounts() failed: %s", e.message);
+				return;
+			}
+
+			string root_path;
+			uint id;
+
+			var mount_iter = reply.get_child_value(0).get_child_value(0).iterator ();
+			while (mount_iter.next ("(su)", out root_path, out id))
+				this.add_mount (root_path, id);
+		});
+	}
+
+	void on_test_mount_service_vanished (DBusConnection connection,
+	                                     string         name) {
+		foreach (Mount m in mount_list)
+			this.mount_removed (m);
+
+		connection.signal_unsubscribe (this.dbus_mount_added_id);
+		connection.signal_unsubscribe (this.dbus_mount_removed_id);
+
+		this.mount_list = null;
+	}
+
+	unowned List<Mount>? find_mount_by_root_path (string root_path) {
+		for (unowned List<Mount> l = this.mount_list; l != null; l = l.next)
+			if (((Tracker.TestMount)l.data).root_path == root_path)
+				return l;
+
+		return null;
+	}
+
+	void add_mount (string root_path,
+	                uint   id) {
+		unowned List<Mount> l = find_mount_by_root_path (root_path);
+
+		if (l != null)
+			return;
+
+		Mount mount = new Tracker.TestMount (root_path, id);
+
+		this.mount_list.prepend (mount);
+
+		this.mount_added (mount);
+	}
+
+	void remove_mount (string root_path) {
+		unowned List<Mount> l = find_mount_by_root_path (root_path);
+
+		if (l == null)
+			return;
+
+		Mount mount = l.data;
+		this.mount_list.delete_link (l);
+		this.mount_removed (mount);
+	}
+
+	void dbus_mount_added_cb (DBusConnection connection,
+	                          string         sender_name,
+	                          string         object_path,
+	                          string         interface_name,
+	                          string         signal_name,
+	                          Variant        parameters) {
+		string root_path;
+		uint id;
+
+		parameters.get ("(su)", out root_path, out id);
+		this.add_mount (root_path, id);
+	}
+
+	void dbus_mount_removed_cb (DBusConnection connection,
+	                            string         sender_name,
+	                            string         object_path,
+	                            string         interface_name,
+	                            string         signal_name,
+	                            Variant        parameters) {
+		string root_path;
+
+		parameters.get ("(s)", out root_path);
+		this.remove_mount (root_path);
+	}
+
+
+	public override bool is_supported () {
+		return true;
+	}
+
+	public override List<unowned Mount> get_mounts () {
+		return this.mount_list.copy ();
+	}
+
+	public override List<Volume> get_volumes () {
+		return null;
+	}
+
+	public override List<Drive> get_connected_drives () {
+		return null;
+	}
+
+	public override Volume get_volume_for_uuid (string uuid) {
+		return null;
+	}
+
+	public override Mount get_mount_for_uuid (string uuid) {
+		return null;
+	}
+
+	public Mount? get_mount_for_mount_path (string mount_path) {
+		foreach (Mount m in this.mount_list) {
+			if (m.get_root().get_path() == mount_path)
+				return m;
+		}
+
+		return null;
+	}
+}
+
+public static void g_io_module_load (IOModule module) {
+	tracker_test_volume_monitor_register_types (module);
+}
+
+public static void g_io_module_unload (IOModule module) {
+}
+
+[CCode (array_length = false)]
+public static string[] g_io_module_query () {
+	return {"gio-volume-monitor"};
+}
+
+[ModuleInit]
+public static void tracker_test_volume_monitor_register_types (TypeModule module) {
+	GLib.IOExtensionPoint.implement ("gio-volume-monitor",
+	                                 typeof (Tracker.TestVolumeMonitor),
+	                                 "tracker-test-volume-monitor",
+	                                 0);
+}
+
diff --git a/utils/tracker-sandbox b/utils/tracker-sandbox
index bf6ee43..a7ff26d 100755
--- a/utils/tracker-sandbox
+++ b/utils/tracker-sandbox
@@ -107,6 +107,13 @@ if [ -n "$PREFIX" ]; then
 	export TRACKER_LANGUAGE_STOPWORDS_DIR="$PREFIX/share/tracker/languages"
 fi
 
+# FIXME: should be in lib/tracker-0.14 ;)
+# Allow use of test mounter, if desired ... this is bit of a black art which
+# requires executing libexec/tracker-test-mount-service and then calling its
+# DBus API manually for now.
+export GIO_EXTRA_MODULES="$(dirname $(which tracker-control))/../lib/tracker"
+export GIO_USE_VOLUME_MONITOR="tracker-test-volume-monitor"
+
 set -o nounset
 
 if [ "$SEPARATE_USER_MODE" != "true" ]; then



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