[tracker-miners/sam/test-removable-devices] functional-tests: Add mock-volume-monitor GIO module
- From: Sam Thursfield <sthursfield src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [tracker-miners/sam/test-removable-devices] functional-tests: Add mock-volume-monitor GIO module
- Date: Wed, 18 Aug 2021 10:38:21 +0000 (UTC)
commit 303ace717905457114a74982942ff1ac5252ae71
Author: Sam Thursfield <sam afuera me uk>
Date: Tue Aug 17 17:28:51 2021 +0200
functional-tests: Add mock-volume-monitor GIO module
This is our best option for testing Tracker's removable device handling
code, see: https://discourse.gnome.org/t/testing-removable-usb-devices/7297
You can test-drive the module by running this command in the build tree:
env GIO_USE_VOLUME_MONITOR=mockvolumemonitor
GIO_MODULE_DIR=$(pwd)/tests/functional-tests/mockvolumemonitor gio mount --monitor
The module is operated over D-Bus, to create a fake mount you can do
this:
gdbus call --session --dest org.freedesktop.Tracker3.MockVolumeMonitor \
--object-path /org/freedesktop/Tracker3/MockVolumeMonitor \
--method org.freedesktop.Tracker3.MockVolumeMonitor.AddMount file:///tmp/mymount
tests/functional-tests/meson.build | 2 +
.../functional-tests/mockvolumemonitor/meson.build | 6 +
.../mockvolumemonitor/mock-drive.c | 246 +++++++++++++++++
.../mockvolumemonitor/mock-drive.h | 26 ++
.../mockvolumemonitor/mock-mount.c | 246 +++++++++++++++++
.../mockvolumemonitor/mock-mount.h | 30 ++
.../mockvolumemonitor/mock-volume-monitor.c | 302 +++++++++++++++++++++
.../mockvolumemonitor/mock-volume-monitor.h | 14 +
.../mockvolumemonitor/mock-volume.c | 252 +++++++++++++++++
.../mockvolumemonitor/mock-volume.h | 34 +++
10 files changed, 1158 insertions(+)
---
diff --git a/tests/functional-tests/meson.build b/tests/functional-tests/meson.build
index 9ed3be7b5..4838dcdaa 100644
--- a/tests/functional-tests/meson.build
+++ b/tests/functional-tests/meson.build
@@ -1,5 +1,7 @@
python = find_program('python3')
+subdir('mockvolumemonitor')
+
# Configure functional tests to run completely from source tree.
testconf = configuration_data()
diff --git a/tests/functional-tests/mockvolumemonitor/meson.build
b/tests/functional-tests/mockvolumemonitor/meson.build
new file mode 100644
index 000000000..fa13238b5
--- /dev/null
+++ b/tests/functional-tests/mockvolumemonitor/meson.build
@@ -0,0 +1,6 @@
+shared_module('mockvolumemonitor',
+ 'mock-drive.c', 'mock-drive.h',
+ 'mock-mount.c', 'mock-mount.h',
+ 'mock-volume.c', 'mock-volume.h',
+ 'mock-volume-monitor.c', 'mock-volume-monitor.h',
+ dependencies: [gio, gio_unix])
diff --git a/tests/functional-tests/mockvolumemonitor/mock-drive.c
b/tests/functional-tests/mockvolumemonitor/mock-drive.c
new file mode 100644
index 000000000..0ab2c9716
--- /dev/null
+++ b/tests/functional-tests/mockvolumemonitor/mock-drive.c
@@ -0,0 +1,246 @@
+#include <glib.h>
+#include <gio/gio.h>
+
+#include "mock-drive.h"
+
+struct _MockDrive
+{
+ GObject parent;
+
+ MockVolumeMonitor *monitor; /* owned by volume monitor */
+ GList *volumes; /* entries in list are owned by volume monitor */
+
+ const gchar *name;
+};
+
+static void mock_drive_drive_iface_init ();
+
+G_DEFINE_TYPE_EXTENDED (MockDrive, mock_drive, G_TYPE_OBJECT, 0,
+ G_IMPLEMENT_INTERFACE (G_TYPE_DRIVE, mock_drive_drive_iface_init))
+
+static void
+mock_drive_finalize (GObject *object)
+{
+ MockDrive *drive = MOCK_DRIVE (object);
+ GList *l;
+
+ for (l = drive->volumes; l != NULL; l = l->next) {
+ MockVolume *volume = l->data;
+ mock_volume_unset_drive (volume, drive);
+ }
+
+ G_OBJECT_CLASS (mock_drive_parent_class)->finalize (object);
+}
+
+static void
+mock_drive_class_init (MockDriveClass *klass)
+{
+ GObjectClass *gobject_class;
+
+ gobject_class = G_OBJECT_CLASS (klass);
+ gobject_class->finalize = mock_drive_finalize;
+}
+
+static void
+mock_drive_init (MockDrive *drive)
+{
+}
+
+emit_changed (MockDrive *drive)
+{
+ g_signal_emit_by_name (drive, "changed");
+ g_signal_emit_by_name (drive->monitor, "drive-changed", drive);
+}
+
+
+MockDrive *
+mock_drive_new (MockVolumeMonitor *monitor,
+ const gchar *name)
+{
+ MockDrive *drive;
+
+ drive = g_object_new (MOCK_TYPE_DRIVE, NULL);
+ drive->monitor = monitor;
+ drive->name = g_strdup (name);
+
+ return drive;
+}
+
+void
+mock_drive_disconnected (MockDrive *drive)
+{
+ GList *l, *volumes;
+
+ volumes = drive->volumes;
+ drive->volumes = NULL;
+ for (l = volumes; l != NULL; l = l->next) {
+ MockVolume *volume = l->data;
+ mock_volume_unset_drive (volume, drive);
+ }
+ g_list_free (volumes);
+}
+
+void
+mock_drive_set_volume (MockDrive *drive,
+ MockVolume *volume)
+{
+ if (g_list_find (drive->volumes, volume) == NULL) {
+ drive->volumes = g_list_prepend (drive->volumes, volume);
+ emit_changed (drive);
+ }
+}
+
+void
+mock_drive_unset_volume (MockDrive *drive,
+ MockVolume *volume)
+{
+ GList *l;
+ l = g_list_find (drive->volumes, volume);
+ if (l != NULL)
+ {
+ drive->volumes = g_list_delete_link (drive->volumes, l);
+ emit_changed (drive);
+ }
+}
+
+static GIcon *
+mock_drive_get_icon (GDrive *_drive)
+{
+ return NULL;
+}
+
+static GIcon *
+mock_drive_get_symbolic_icon (GDrive *_drive)
+{
+ return NULL;
+}
+
+static char *
+mock_drive_get_name (GDrive *_drive)
+{
+ MockDrive *drive = MOCK_DRIVE (_drive);
+ return g_strdup (drive->name);
+}
+
+static GList *
+mock_drive_get_volumes (GDrive *_drive)
+{
+ MockDrive *drive = MOCK_DRIVE (_drive);
+ GList *l;
+ l = g_list_copy (drive->volumes);
+ g_list_foreach (l, (GFunc) g_object_ref, NULL);
+ return l;
+}
+
+static gboolean
+mock_drive_has_volumes (GDrive *_drive)
+{
+ MockDrive *drive = MOCK_DRIVE (_drive);
+ gboolean res;
+ res = drive->volumes != NULL;
+ return res;
+}
+
+static gboolean
+mock_drive_is_removable (GDrive *_drive)
+{
+ return TRUE;
+}
+
+static gboolean
+mock_drive_is_media_removable (GDrive *_drive)
+{
+ return FALSE;
+}
+
+static gboolean
+mock_drive_has_media (GDrive *_drive)
+{
+ return TRUE;
+}
+
+static gboolean
+mock_drive_is_media_check_automatic (GDrive *_drive)
+{
+ return TRUE;
+}
+
+static gboolean
+mock_drive_can_eject (GDrive *_drive)
+{
+ return FALSE;
+}
+
+static gboolean
+mock_drive_can_poll_for_media (GDrive *_drive)
+{
+ return FALSE;
+}
+
+static gboolean
+mock_drive_can_start (GDrive *_drive)
+{
+ return FALSE;
+}
+
+static gboolean
+mock_drive_can_start_degraded (GDrive *_drive)
+{
+ return FALSE;
+}
+
+static gboolean
+mock_drive_can_stop (GDrive *_drive)
+{
+ return FALSE;
+}
+
+static GDriveStartStopType
+mock_drive_get_start_stop_type (GDrive *_drive)
+{
+ return G_DRIVE_START_STOP_TYPE_SHUTDOWN;
+}
+
+/* ---------------------------------------------------------------------------------------------------- */
+
+static char *
+mock_drive_get_identifier (GDrive *_drive,
+ const gchar *kind)
+{
+ return NULL;
+}
+
+static gchar **
+mock_drive_enumerate_identifiers (GDrive *_drive)
+{
+ return NULL;
+}
+
+static const gchar *
+mock_drive_get_sort_key (GDrive *_drive)
+{
+ return NULL;
+}
+
+static void
+mock_drive_drive_iface_init (GDriveIface *iface)
+{
+ iface->get_name = mock_drive_get_name;
+ iface->get_icon = mock_drive_get_icon;
+ iface->get_symbolic_icon = mock_drive_get_symbolic_icon;
+ iface->has_volumes = mock_drive_has_volumes;
+ iface->get_volumes = mock_drive_get_volumes;
+ iface->is_removable = mock_drive_is_removable;
+ iface->is_media_removable = mock_drive_is_media_removable;
+ iface->has_media = mock_drive_has_media;
+ iface->is_media_check_automatic = mock_drive_is_media_check_automatic;
+ iface->can_eject = mock_drive_can_eject;
+ iface->can_poll_for_media = mock_drive_can_poll_for_media;
+ iface->get_identifier = mock_drive_get_identifier;
+ iface->enumerate_identifiers = mock_drive_enumerate_identifiers;
+ iface->get_start_stop_type = mock_drive_get_start_stop_type;
+ iface->can_start = mock_drive_can_start;
+ iface->can_start_degraded = mock_drive_can_start_degraded;
+ iface->can_stop = mock_drive_can_stop;
+ iface->get_sort_key = mock_drive_get_sort_key;
+}
diff --git a/tests/functional-tests/mockvolumemonitor/mock-drive.h
b/tests/functional-tests/mockvolumemonitor/mock-drive.h
new file mode 100644
index 000000000..0dee6820f
--- /dev/null
+++ b/tests/functional-tests/mockvolumemonitor/mock-drive.h
@@ -0,0 +1,26 @@
+#ifndef __MOCK_DRIVE_H__
+#define __MOCK_DRIVE_H__
+
+#include <glib-object.h>
+#include <gio/gio.h>
+#include <gio/gunixmounts.h>
+
+#include "mock-volume-monitor.h"
+#include "mock-volume.h"
+
+G_BEGIN_DECLS
+
+#define MOCK_TYPE_DRIVE (mock_drive_get_type ())
+G_DECLARE_FINAL_TYPE (MockDrive, mock_drive, MOCK, DRIVE, GObject)
+
+MockDrive *mock_drive_new (MockVolumeMonitor *monitor,
+ const gchar *name);
+void mock_drive_disconnected (MockDrive *drive);
+void mock_drive_set_volume (MockDrive *drive,
+ MockVolume *volume);
+void mock_drive_unset_volume (MockDrive *drive,
+ MockVolume *volume);
+
+G_END_DECLS
+
+#endif /* __MOCK_DRIVE_H__ */
diff --git a/tests/functional-tests/mockvolumemonitor/mock-mount.c
b/tests/functional-tests/mockvolumemonitor/mock-mount.c
new file mode 100644
index 000000000..053533f68
--- /dev/null
+++ b/tests/functional-tests/mockvolumemonitor/mock-mount.c
@@ -0,0 +1,246 @@
+#include <glib.h>
+#include <gio/gio.h>
+
+#include "mock-mount.h"
+#include "mock-volume.h"
+
+struct _MockMount
+{
+ GObject parent;
+
+ MockVolumeMonitor *monitor; /* owned by volume monitor */
+
+ /* may be NULL */
+ MockVolume *volume; /* owned by volume monitor */
+
+ gchar *name;
+ GFile *root;
+};
+
+static void mock_mount_mount_iface_init (GMountIface *iface);
+
+G_DEFINE_TYPE_EXTENDED (MockMount, mock_mount, G_TYPE_OBJECT, 0,
+ G_IMPLEMENT_INTERFACE (G_TYPE_MOUNT,
+ mock_mount_mount_iface_init))
+
+static void on_volume_changed (GVolume *volume, gpointer user_data);
+
+static void
+mock_mount_finalize (GObject *object)
+{
+ MockMount *mount = MOCK_MOUNT (object);
+
+ if (mount->volume != NULL) {
+ g_signal_handlers_disconnect_by_func (mount->volume, on_volume_changed, mount);
+ mock_volume_unset_mount (mount->volume, mount);
+ }
+
+ g_free (mount->name);
+ g_clear_object (&mount->root);
+
+ G_OBJECT_CLASS (mock_mount_parent_class)->finalize (object);
+}
+
+static void
+mock_mount_class_init (MockMountClass *klass)
+{
+ GObjectClass *gobject_class;
+
+ gobject_class = G_OBJECT_CLASS (klass);
+ gobject_class->finalize = mock_mount_finalize;
+}
+
+static void
+mock_mount_init (MockMount *mount)
+{
+}
+
+static void
+emit_changed (MockMount *mount)
+{
+ g_signal_emit_by_name (mount, "changed");
+ g_signal_emit_by_name (mount->monitor, "mount-changed", mount);
+}
+
+static void
+on_volume_changed (GVolume *volume,
+ gpointer user_data)
+{
+ MockMount *mount = MOCK_MOUNT (user_data);
+ emit_changed (mount);
+}
+
+MockMount *
+mock_mount_new (MockVolumeMonitor *monitor,
+ MockVolume *volume,
+ const gchar *name,
+ GFile *root)
+{
+ MockMount *mount = NULL;
+
+ mount = g_object_new (MOCK_TYPE_MOUNT, NULL);
+ mount->monitor = monitor;
+ mount->name = g_strdup (name);
+ mount->root = g_object_ref (root);
+
+ /* need to set the volume only when the mount is fully constructed */
+ mount->volume = volume;
+ if (mount->volume != NULL) {
+ mock_volume_set_mount (volume, mount);
+ /* this is for piggy backing on the name and icon of the associated volume */
+ g_signal_connect (mount->volume, "changed", G_CALLBACK (on_volume_changed), mount);
+ }
+
+ return mount;
+}
+
+void
+mock_mount_unmounted (MockMount *mount)
+{
+ if (mount->volume != NULL) {
+ mock_volume_unset_mount (mount->volume, mount);
+ g_signal_handlers_disconnect_by_func (mount->volume, on_volume_changed, mount);
+ mount->volume = NULL;
+ emit_changed (mount);
+ }
+}
+
+void
+mock_mount_unset_volume (MockMount *mount,
+ MockVolume *volume)
+{
+ if (mount->volume == volume) {
+ g_signal_handlers_disconnect_by_func (mount->volume, on_volume_changed, mount);
+ mount->volume = NULL;
+ emit_changed (mount);
+ }
+}
+
+void
+mock_mount_set_volume (MockMount *mount,
+ MockVolume *volume)
+{
+ if (mount->volume != volume) {
+ if (mount->volume != NULL)
+ mock_mount_unset_volume (mount, mount->volume);
+ mount->volume = volume;
+ if (mount->volume != NULL) {
+ mock_volume_set_mount (volume, mount);
+ /* this is for piggy backing on the name and icon of the associated volume */
+ g_signal_connect (mount->volume, "changed", G_CALLBACK (on_volume_changed), mount);
+ }
+ emit_changed (mount);
+ }
+}
+
+static GFile *
+mock_mount_get_root (GMount *_mount)
+{
+ MockMount *mount = MOCK_MOUNT (_mount);
+ return g_object_ref (mount->root);
+}
+
+static GIcon *
+mock_mount_get_icon (GMount *_mount)
+{
+ return NULL;
+}
+
+static GIcon *
+mock_mount_get_symbolic_icon (GMount *_mount)
+{
+ return NULL;
+}
+
+static gchar *
+mock_mount_get_uuid (GMount *_mount)
+{
+ return NULL;
+}
+
+static gchar *
+mock_mount_get_name (GMount *_mount)
+{
+ MockMount *mount = MOCK_MOUNT (_mount);
+ return g_strdup (mount->name);
+}
+
+gboolean
+mock_mount_has_uuid (MockMount *_mount,
+ const gchar *uuid)
+{
+ return FALSE;
+}
+
+const gchar *
+mock_mount_get_mount_path (MockMount *mount)
+{
+ return NULL;
+}
+
+GUnixMountEntry *
+mock_mount_get_mount_entry (MockMount *_mount)
+{
+ return NULL;
+}
+
+static GDrive *
+mock_mount_get_drive (GMount *_mount)
+{
+ MockMount *mount = MOCK_MOUNT (_mount);
+ GDrive *drive = NULL;
+
+ if (mount->volume != NULL)
+ drive = g_volume_get_drive (G_VOLUME (mount->volume));
+ return drive;
+}
+
+static GVolume *
+mock_mount_get_volume_ (GMount *_mount)
+{
+ MockMount *mount = MOCK_MOUNT (_mount);
+ GVolume *volume = NULL;
+
+ if (mount->volume != NULL)
+ volume = G_VOLUME (g_object_ref (mount->volume));
+ return volume;
+}
+
+static gboolean
+mock_mount_can_unmount (GMount *_mount)
+{
+ return TRUE;
+}
+
+static gboolean
+mock_mount_can_eject (GMount *_mount)
+{
+ return FALSE;
+}
+
+static const gchar *
+mock_mount_get_sort_key (GMount *_mount)
+{
+ return NULL;
+}
+
+static void
+mock_mount_mount_iface_init (GMountIface *iface)
+{
+ iface->get_root = mock_mount_get_root;
+ iface->get_name = mock_mount_get_name;
+ iface->get_icon = mock_mount_get_icon;
+ iface->get_symbolic_icon = mock_mount_get_symbolic_icon;
+ iface->get_uuid = mock_mount_get_uuid;
+ iface->get_drive = mock_mount_get_drive;
+ iface->get_volume = mock_mount_get_volume_;
+ iface->can_unmount = mock_mount_can_unmount;
+ iface->can_eject = mock_mount_can_eject;
+ iface->get_sort_key = mock_mount_get_sort_key;
+}
+
+MockVolume *
+mock_mount_get_volume (MockMount *mount)
+{
+ return mount->volume;
+}
diff --git a/tests/functional-tests/mockvolumemonitor/mock-mount.h
b/tests/functional-tests/mockvolumemonitor/mock-mount.h
new file mode 100644
index 000000000..17938443b
--- /dev/null
+++ b/tests/functional-tests/mockvolumemonitor/mock-mount.h
@@ -0,0 +1,30 @@
+#ifndef __MOCK_MOUNT_H__
+#define __MOCK_MOUNT_H__
+
+#include <glib-object.h>
+#include <gio/gio.h>
+#include <gio/gunixmounts.h>
+
+#include "mock-volume-monitor.h"
+
+G_BEGIN_DECLS
+
+#define MOCK_TYPE_MOUNT (mock_mount_get_type ())
+G_DECLARE_FINAL_TYPE (MockMount, mock_mount, MOCK, MOUNT, GObject)
+
+
+MockMount *mock_mount_new (MockVolumeMonitor *monitor,
+ MockVolume *volume,
+ const gchar *name,
+ GFile *root);
+void mock_mount_unmounted (MockMount *mount);
+
+void mock_mount_set_volume (MockMount *mount,
+ MockVolume *volume);
+void mock_mount_unset_volume (MockMount *mount,
+ MockVolume *volume);
+MockVolume *mock_mount_get_volume (MockMount *mount);
+
+G_END_DECLS
+
+#endif /* __MOCK_MOUNT_H__ */
diff --git a/tests/functional-tests/mockvolumemonitor/mock-volume-monitor.c
b/tests/functional-tests/mockvolumemonitor/mock-volume-monitor.c
new file mode 100644
index 000000000..a98893335
--- /dev/null
+++ b/tests/functional-tests/mockvolumemonitor/mock-volume-monitor.c
@@ -0,0 +1,302 @@
+#include "mock-volume-monitor.h"
+#include "mock-drive.h"
+#include "mock-volume.h"
+#include "mock-mount.h"
+
+struct _MockVolumeMonitor {
+ GNativeVolumeMonitor parent;
+
+ GDBusNodeInfo *node_info;
+ guint bus_token;
+ guint object_token;
+
+ GList *drives;
+ GList *volumes;
+ GList *mounts;
+
+ gint counter;
+};
+
+G_DEFINE_TYPE (MockVolumeMonitor, mock_volume_monitor, G_TYPE_NATIVE_VOLUME_MONITOR);
+
+
+static void
+add_mock_mount (MockVolumeMonitor *self, const gchar *uri)
+{
+ int id = self->counter ++;
+ g_autofree gchar *drive_name;
+ g_autofree gchar *volume_name;
+ g_autofree gchar *mount_name;
+ MockDrive *drive;
+ MockVolume *volume;
+ MockMount *mount;
+ g_autoptr(GFile) root = NULL;
+
+ g_message ("Adding mock mount at '%s'", uri);
+
+ drive_name = g_strdup_printf ("MockDrive%i", id);
+ volume_name = g_strdup_printf ("MockVolume%i", id);
+ mount_name = g_strdup_printf ("MockMount%i", id);
+
+ root = g_file_new_for_uri (uri);
+
+ drive = mock_drive_new (self, drive_name);
+ volume = mock_volume_new (self, drive, volume_name);
+ mount = mock_mount_new (self, volume, mount_name, root);
+
+ self->drives = g_list_prepend (self->drives, drive);
+ self->volumes = g_list_prepend (self->volumes, volume);
+ self->mounts = g_list_prepend (self->mounts, mount);
+
+ g_signal_emit_by_name (self, "drive-connected", drive);
+ g_signal_emit_by_name (self, "volume-added", volume);
+ g_signal_emit_by_name (self, "mount-added", mount);
+}
+
+static gint
+match_mount_by_root (gconstpointer a, gconstpointer b)
+{
+ GMount *mount = G_MOUNT (a);
+ GFile *root = G_FILE (b);
+
+ return g_file_equal (g_mount_get_root (mount), root);
+}
+
+static void
+remove_mock_mount (MockVolumeMonitor *self, const gchar *uri)
+{
+ GList *node;
+ g_autoptr(GDrive) drive = NULL;
+ g_autoptr(GVolume) volume = NULL;
+ g_autoptr(MockMount) mount = NULL;
+ g_autoptr(GFile) root = NULL;
+
+ g_message ("Removing mock mount at '%s'", uri);
+
+ root = g_file_new_for_uri (uri);
+ node = g_list_find_custom (self->mounts, root, match_mount_by_root);
+
+ if (!node) {
+ g_warning ("No mount found with root %s", uri);
+ return;
+ }
+
+ mount = MOCK_MOUNT (node->data);
+ volume = g_mount_get_volume (G_MOUNT (mount));
+ drive = g_volume_get_drive (volume);
+
+ mock_mount_unmounted (mount);
+ mock_volume_removed (MOCK_VOLUME (volume));
+ mock_drive_disconnected (MOCK_DRIVE (drive));
+
+ g_signal_emit_by_name (self, "mount-removed", mount);
+ g_signal_emit_by_name (self, "volume-removed", volume);
+ g_signal_emit_by_name (self, "drive-disconnected", drive);
+
+ self->drives = g_list_remove (self->drives, drive);
+ self->volumes = g_list_remove (self->volumes, volume);
+ self->mounts = g_list_remove (self->mounts, mount);
+}
+
+
+/* DBus interface
+ * --------------
+ *
+ * Used by tests to control the MockVolumeMonitor object.
+ */
+
+#define BUS_NAME "org.freedesktop.Tracker.MockVolumeMonitor"
+#define BUS_PATH "/org/freedesktop/Tracker/MockVolumeMonitor"
+
+static const gchar dbus_xml[] =
+ "<node>"
+ " <interface name='org.freedesktop.Tracker.MockVolumeMonitor'>"
+ " <method name='AddMount'>"
+ " <arg type='s' name='path' direction='in' />"
+ " </method>"
+ " <method name='RemoveMount'>"
+ " <arg type='s' name='path' direction='in' />"
+ " </method>"
+ " </interface>"
+ "</node>";
+
+
+static void
+on_dbus_method_call (GDBusConnection *connection,
+ const gchar *sender,
+ const gchar *object_path,
+ const gchar *interface_name,
+ const gchar *method_name,
+ GVariant *parameters,
+ GDBusMethodInvocation *invocation,
+ gpointer user_data)
+{
+ MockVolumeMonitor *self = MOCK_VOLUME_MONITOR (user_data);
+
+ if (g_strcmp0 (method_name, "AddMount") == 0) {
+ g_autofree gchar *uri = NULL;
+
+ g_variant_get (parameters, "(s)", &uri);
+
+ add_mock_mount (self, uri);
+ } else if (g_strcmp0 (method_name, "RemoveMount") == 0) {
+ g_autofree gchar *uri = NULL;
+
+ g_variant_get (parameters, "(s)", &uri);
+
+ remove_mock_mount (self, uri);
+ } else {
+ g_dbus_method_invocation_return_error (invocation,
+ G_DBUS_ERROR,
+ G_DBUS_ERROR_UNKNOWN_METHOD,
+ "Unknown method on DBus interface: '%s'", method_name);
+ }
+
+}
+
+static void
+on_bus_acquired (GDBusConnection *connection, const gchar *name, gpointer user_data)
+{
+ MockVolumeMonitor *self = MOCK_VOLUME_MONITOR (user_data);
+ GError *error = NULL;
+
+ g_message ("Publishing DBus object at " BUS_PATH);
+
+ self->node_info= g_dbus_node_info_new_for_xml (dbus_xml, &error);
+ g_assert_no_error (error);
+
+ self->object_token =
+ g_dbus_connection_register_object (connection,
+ BUS_PATH,
+ self->node_info->interfaces[0],
+ &(GDBusInterfaceVTable) { on_dbus_method_call, NULL, NULL
},
+ self,
+ NULL,
+ &error);
+}
+
+static void
+on_bus_name_acquired (GDBusConnection *connection,
+ const gchar *name,
+ gpointer user_data)
+{
+ g_message ("Acquired name: %s", name);
+}
+
+static void
+on_bus_name_lost (GDBusConnection *connection,
+ const gchar *name,
+ gpointer user_data)
+{
+ MockVolumeMonitor *self = MOCK_VOLUME_MONITOR (user_data);
+ g_message ("Lost name: %s", name);
+
+ g_dbus_connection_unregister_object (connection, self->object_token);
+ self->object_token = 0;
+}
+
+/* GVolumeMonitor implementation
+ * -----------------------------
+ *
+ * We inject fake mounts into current process by replacing the usual
+ * GNativeVolumeMonitor implementation with this.
+ */
+
+static gboolean
+is_supported (void)
+{
+ g_debug (__func__);
+ return TRUE;
+}
+
+static GList *
+get_connected_drives (GVolumeMonitor *volume_monitor)
+{
+ MockVolumeMonitor *self = MOCK_VOLUME_MONITOR (volume_monitor);
+ return self->drives;
+}
+
+static GList *
+get_volumes (GVolumeMonitor *volume_monitor)
+{
+ MockVolumeMonitor *self = MOCK_VOLUME_MONITOR (volume_monitor);
+ return self->volumes;
+}
+
+static GList *
+get_mounts (GVolumeMonitor *volume_monitor)
+{
+ MockVolumeMonitor *self = MOCK_VOLUME_MONITOR (volume_monitor);
+ return self->mounts;
+}
+
+static GVolume *
+get_volume_for_uuid (GVolumeMonitor *volume_monitor,
+ const char *uuid)
+{
+ return NULL;
+
+}
+
+static GMount *
+get_mount_for_uuid (GVolumeMonitor *volume_monitor,
+ const char *uuid)
+{
+ return NULL;
+}
+
+static GVolume *
+adopt_orphan_mount (GMount *mount,
+ GVolumeMonitor *volume_monitor)
+{
+ return NULL;
+}
+
+void
+drive_eject_button (GVolumeMonitor *volume_monitor,
+ GDrive *drive)
+{
+}
+
+void
+drive_stop_button (GVolumeMonitor *volume_monitor,
+ GDrive *drive)
+{
+}
+
+
+static void mock_volume_monitor_init (MockVolumeMonitor *self) {
+ self->bus_token = g_bus_own_name (G_BUS_TYPE_SESSION, BUS_NAME, G_BUS_NAME_OWNER_FLAGS_NONE,
+ on_bus_acquired,
+ on_bus_name_acquired,
+ on_bus_name_lost,
+ g_object_ref (self),
+ g_object_unref);
+}
+
+static void mock_volume_monitor_class_init (MockVolumeMonitorClass *klass) {
+ GVolumeMonitorClass *monitor_class = G_VOLUME_MONITOR_CLASS (klass);
+
+ monitor_class->is_supported = is_supported;
+ monitor_class->get_connected_drives = get_connected_drives;
+ monitor_class->get_volumes = get_volumes;
+ monitor_class->get_mounts = get_mounts;
+ monitor_class->get_volume_for_uuid = get_volume_for_uuid;
+ monitor_class->get_mount_for_uuid = get_mount_for_uuid;
+ monitor_class->adopt_orphan_mount = adopt_orphan_mount;
+ monitor_class->drive_eject_button = drive_eject_button;
+ monitor_class->drive_stop_button = drive_stop_button;
+}
+
+void g_io_module_load (GIOModule *module) {
+ g_debug (__func__);
+
+ g_type_module_use (G_TYPE_MODULE (module));
+
+ g_io_extension_point_implement (
+ G_NATIVE_VOLUME_MONITOR_EXTENSION_POINT_NAME,
+ MOCK_TYPE_VOLUME_MONITOR, "mockvolumemonitor", 0);
+}
+
+void g_io_module_unload (GIOModule *module) {
+}
diff --git a/tests/functional-tests/mockvolumemonitor/mock-volume-monitor.h
b/tests/functional-tests/mockvolumemonitor/mock-volume-monitor.h
new file mode 100644
index 000000000..6728bc81b
--- /dev/null
+++ b/tests/functional-tests/mockvolumemonitor/mock-volume-monitor.h
@@ -0,0 +1,14 @@
+#ifndef __MOCK_VOLUME_MONITOR_H__
+#define __MOCK_VOLUME_MONITOR_H__
+
+#include <gio/gio.h>
+
+#define MOCK_TYPE_VOLUME_MONITOR mock_volume_monitor_get_type()
+G_DECLARE_FINAL_TYPE (MockVolumeMonitor, mock_volume_monitor, MOCK, VOLUME_MONITOR, GNativeVolumeMonitor)
+
+/* Forward definitions */
+typedef struct _MockDrive MockDrive;
+typedef struct _MockVolume MockVolume;
+typedef struct _MockMount MockMount;
+
+#endif
diff --git a/tests/functional-tests/mockvolumemonitor/mock-volume.c
b/tests/functional-tests/mockvolumemonitor/mock-volume.c
new file mode 100644
index 000000000..8cd24c6cd
--- /dev/null
+++ b/tests/functional-tests/mockvolumemonitor/mock-volume.c
@@ -0,0 +1,252 @@
+#include <glib.h>
+#include <gio/gio.h>
+
+#include "mock-volume.h"
+
+struct _MockVolume
+{
+ GObject parent;
+
+ MockVolumeMonitor *monitor; /* owned by volume monitor */
+ MockMount *mount; /* owned by volume monitor */
+ MockDrive *drive; /* owned by volume monitor */
+
+ gchar *name;
+ gchar *uuid;
+};
+
+static void mock_volume_volume_iface_init (GVolumeIface *iface);
+
+G_DEFINE_TYPE_EXTENDED (MockVolume, mock_volume, G_TYPE_OBJECT, 0,
+ G_IMPLEMENT_INTERFACE (G_TYPE_VOLUME, mock_volume_volume_iface_init))
+
+static void
+mock_volume_finalize (GObject *object)
+{
+ MockVolume *volume = MOCK_VOLUME (object);
+
+ if (volume->mount != NULL) {
+ mock_mount_unset_volume (volume->mount, volume);
+ }
+
+ if (volume->drive != NULL) {
+ mock_drive_unset_volume (volume->drive, volume);
+ }
+
+ g_free (volume->name);
+ g_free (volume->uuid);
+
+ G_OBJECT_CLASS (mock_volume_parent_class)->finalize (object);
+}
+
+static void
+mock_volume_class_init (MockVolumeClass *klass)
+{
+ GObjectClass *gobject_class;
+
+ gobject_class = G_OBJECT_CLASS (klass);
+ gobject_class->finalize = mock_volume_finalize;
+}
+
+static void
+mock_volume_init (MockVolume *volume)
+{
+}
+
+static void
+emit_changed (MockVolume *volume)
+{
+ g_signal_emit_by_name (volume, "changed");
+ g_signal_emit_by_name (volume->monitor, "volume-changed", volume);
+}
+
+
+MockVolume *
+mock_volume_new (MockVolumeMonitor *monitor,
+ MockDrive *drive,
+ const gchar *name)
+{
+ MockVolume *volume;
+
+ volume = g_object_new (MOCK_TYPE_VOLUME, NULL);
+ volume->monitor = monitor;
+
+ volume->drive = drive;
+ if (drive != NULL)
+ mock_drive_set_volume (drive, volume);
+
+ volume->name = g_strdup (name);
+ volume->uuid = g_uuid_string_random ();
+
+ return volume;
+}
+
+void
+mock_volume_removed (MockVolume *volume)
+{
+ if (volume->mount != NULL) {
+ mock_mount_unset_volume (volume->mount, volume);
+ volume->mount = NULL;
+ }
+
+ if (volume->drive != NULL) {
+ mock_drive_unset_volume (volume->drive, volume);
+ volume->drive = NULL;
+ }
+}
+
+void
+mock_volume_set_mount (MockVolume *volume,
+ MockMount *mount)
+{
+ if (volume->mount != mount) {
+ if (volume->mount != NULL)
+ mock_mount_unset_volume (volume->mount, volume);
+
+ volume->mount = mount;
+
+ emit_changed (volume);
+ }
+}
+
+void
+mock_volume_unset_mount (MockVolume *volume,
+ MockMount *mount)
+{
+ if (volume->mount == mount) {
+ volume->mount = NULL;
+ emit_changed (volume);
+ }
+}
+
+void
+mock_volume_set_drive (MockVolume *volume,
+ MockDrive *drive)
+{
+ if (volume->drive != drive) {
+ if (volume->drive != NULL)
+ mock_drive_unset_volume (volume->drive, volume);
+ volume->drive = drive;
+ emit_changed (volume);
+ }
+}
+
+void
+mock_volume_unset_drive (MockVolume *volume,
+ MockDrive *drive)
+{
+ if (volume->drive == drive) {
+ volume->drive = NULL;
+ emit_changed (volume);
+ }
+}
+
+static GIcon *
+mock_volume_get_icon (GVolume *_volume)
+{
+ return NULL;
+}
+
+static GIcon *
+mock_volume_get_symbolic_icon (GVolume *_volume)
+{
+ return NULL;
+}
+
+static char *
+mock_volume_get_name (GVolume *_volume)
+{
+ MockVolume *volume = MOCK_VOLUME (_volume);
+ return g_strdup (volume->name);
+}
+
+static char *
+mock_volume_get_uuid (GVolume *_volume)
+{
+ MockVolume *volume = MOCK_VOLUME (_volume);
+ return g_strdup (volume->uuid);
+}
+
+static gboolean
+mock_volume_can_mount (GVolume *_volume)
+{
+ return TRUE;
+}
+
+static gboolean
+mock_volume_can_eject (GVolume *_volume)
+{
+ return FALSE;
+}
+
+static gboolean
+mock_volume_should_automount (GVolume *_volume)
+{
+ return TRUE;
+}
+
+static GDrive *
+mock_volume_get_drive (GVolume *_volume)
+{
+ MockVolume *volume = MOCK_VOLUME (_volume);
+ GDrive *drive = NULL;
+
+ if (volume->drive != NULL)
+ drive = G_DRIVE (g_object_ref (volume->drive));
+ return drive;
+}
+
+static GMount *
+mock_volume_get_mount (GVolume *_volume)
+{
+ MockVolume *volume = MOCK_VOLUME (_volume);
+ GMount *mount = NULL;
+
+ if (volume->mount != NULL)
+ mount = G_MOUNT (g_object_ref (volume->mount));
+ return mount;
+}
+
+static gchar *
+mock_volume_get_identifier (GVolume *_volume,
+ const gchar *kind)
+{
+ return g_strdup ("device");
+}
+
+static gchar **
+mock_volume_enumerate_identifiers (GVolume *_volume)
+{
+ return NULL;
+}
+
+static GFile *
+mock_volume_get_activation_root (GVolume *_volume)
+{
+ return NULL;
+}
+
+static const gchar *
+mock_volume_get_sort_key (GVolume *_volume)
+{
+ return NULL;
+}
+
+static void
+mock_volume_volume_iface_init (GVolumeIface *iface)
+{
+ iface->get_name = mock_volume_get_name;
+ iface->get_icon = mock_volume_get_icon;
+ iface->get_symbolic_icon = mock_volume_get_symbolic_icon;
+ iface->get_uuid = mock_volume_get_uuid;
+ iface->get_drive = mock_volume_get_drive;
+ iface->get_mount = mock_volume_get_mount;
+ iface->can_mount = mock_volume_can_mount;
+ iface->can_eject = mock_volume_can_eject;
+ iface->should_automount = mock_volume_should_automount;
+ iface->get_activation_root = mock_volume_get_activation_root;
+ iface->enumerate_identifiers = mock_volume_enumerate_identifiers;
+ iface->get_identifier = mock_volume_get_identifier;
+
+ iface->get_sort_key = mock_volume_get_sort_key;
+}
diff --git a/tests/functional-tests/mockvolumemonitor/mock-volume.h
b/tests/functional-tests/mockvolumemonitor/mock-volume.h
new file mode 100644
index 000000000..9d9c23bc4
--- /dev/null
+++ b/tests/functional-tests/mockvolumemonitor/mock-volume.h
@@ -0,0 +1,34 @@
+#ifndef __MOCK_VOLUME_H__
+#define __MOCK_VOLUME_H__
+
+#include <glib-object.h>
+#include <gio/gio.h>
+#include <gio/gunixmounts.h>
+
+#include "mock-volume-monitor.h"
+
+G_BEGIN_DECLS
+
+#define MOCK_TYPE_VOLUME (mock_volume_get_type ())
+G_DECLARE_FINAL_TYPE (MockVolume, mock_volume, MOCK, VOLUME, GObject)
+
+MockVolume *mock_volume_new (MockVolumeMonitor *monitor,
+ MockDrive *drive,
+ const gchar *name);
+void mock_volume_removed (MockVolume *volume);
+
+GUnixMountPoint *mock_volume_get_mount_point (MockVolume *volume);
+
+void mock_volume_set_mount (MockVolume *volume,
+ MockMount *mount);
+void mock_volume_unset_mount (MockVolume *volume,
+ MockMount *mount);
+
+void mock_volume_set_drive (MockVolume *volume,
+ MockDrive *drive);
+void mock_volume_unset_drive (MockVolume *volume,
+ MockDrive *drive);
+
+G_END_DECLS
+
+#endif /* __MOCK_VOLUME_H__ */
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]