2013-06-08 23:31:09 +02:00
|
|
|
/*
|
|
|
|
* Copyright © 2013 Canonical Limited
|
2024-09-24 14:12:15 +02:00
|
|
|
* Copyright © 2024 GNOME Foundation Inc.
|
2013-06-08 23:31:09 +02:00
|
|
|
*
|
2022-05-18 10:20:07 +02:00
|
|
|
* SPDX-License-Identifier: LGPL-2.1-or-later
|
|
|
|
*
|
2017-05-27 17:19:21 +02:00
|
|
|
* This library 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.
|
2013-06-08 23:31:09 +02:00
|
|
|
*
|
|
|
|
* This 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
|
|
|
|
* Lesser General Public License for more details.
|
|
|
|
*
|
|
|
|
* You should have received a copy of the GNU Lesser General
|
2014-01-23 12:58:29 +01:00
|
|
|
* Public License along with this library; if not, see <http://www.gnu.org/licenses/>.
|
2013-06-08 23:31:09 +02:00
|
|
|
*
|
|
|
|
* Authors: Ryan Lortie <desrt@desrt.ca>
|
2024-09-24 14:12:15 +02:00
|
|
|
* Julian Sparber <jsparber@gnome.org>
|
2013-06-08 23:31:09 +02:00
|
|
|
*/
|
|
|
|
|
|
|
|
#include <gio/gio.h>
|
|
|
|
#include <gio/gdesktopappinfo.h>
|
|
|
|
|
|
|
|
#include "gdbus-sessionbus.h"
|
2024-09-24 14:12:15 +02:00
|
|
|
#include "fake-desktop-portal.h"
|
tests: Move fake-document-portal subprocess inside dbus-appinfo test
For the reasons given in
https://gitlab.gnome.org/GNOME/glib/-/merge_requests/4176#note_2233317,
it’s best to not rely on subprocesses when writing tests. Spawning a
subprocess can go wrong, getting feedback and assertion data from a
subprocess is a pain, and making sure the subprocess is killed properly
at the end of the test is hard to get right.
For tests where we are trying to mock a D-Bus service, it’s much more
reliable to run that service in-process (either in the main thread or in
a separate thread).
So, do that for the `fake-document-portal` former subprocess in the
`dbus-appinfo` test: move it to a worker thread.
This speeds the test up, simplifies the build slightly, and should make
the test run more reliable.
In particular, it provides a pattern for future `fake-*-portal` tests to
be built off. This is particularly useful for more complex portals,
where data needs to be relayed back from the mock portal service to the
unit test to check that the code under test has behaved properly. That’s
a pain to do from a subprocess.
Delete the `org.freedesktop.portal.Documents.service` file because we no
longer need to rely on D-Bus service activation within the test, as
we’re setting up the mock service thread explicitly now.
Signed-off-by: Philip Withnall <pwithnall@gnome.org>
2024-09-27 18:06:40 +02:00
|
|
|
#include "fake-document-portal.h"
|
2013-06-08 23:31:09 +02:00
|
|
|
|
|
|
|
static GDesktopAppInfo *appinfo;
|
|
|
|
static int current_state;
|
|
|
|
static gboolean saw_startup_id;
|
|
|
|
static gboolean requested_startup_id;
|
|
|
|
|
|
|
|
|
|
|
|
static GType test_app_launch_context_get_type (void);
|
|
|
|
typedef GAppLaunchContext TestAppLaunchContext;
|
|
|
|
typedef GAppLaunchContextClass TestAppLaunchContextClass;
|
|
|
|
G_DEFINE_TYPE (TestAppLaunchContext, test_app_launch_context, G_TYPE_APP_LAUNCH_CONTEXT)
|
|
|
|
|
|
|
|
static gchar *
|
|
|
|
test_app_launch_context_get_startup_notify_id (GAppLaunchContext *context,
|
|
|
|
GAppInfo *info,
|
|
|
|
GList *uris)
|
|
|
|
{
|
|
|
|
requested_startup_id = TRUE;
|
|
|
|
return g_strdup ("expected startup id");
|
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
|
|
test_app_launch_context_init (TestAppLaunchContext *ctx)
|
|
|
|
{
|
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
|
|
test_app_launch_context_class_init (GAppLaunchContextClass *class)
|
|
|
|
{
|
|
|
|
class->get_startup_notify_id = test_app_launch_context_get_startup_notify_id;
|
|
|
|
}
|
|
|
|
|
|
|
|
static GType test_application_get_type (void);
|
|
|
|
typedef GApplication TestApplication;
|
|
|
|
typedef GApplicationClass TestApplicationClass;
|
|
|
|
G_DEFINE_TYPE (TestApplication, test_application, G_TYPE_APPLICATION)
|
|
|
|
|
|
|
|
static void
|
|
|
|
saw_action (const gchar *action)
|
|
|
|
{
|
|
|
|
/* This is the main driver of the test. It's a bit of a state
|
|
|
|
* machine.
|
|
|
|
*
|
|
|
|
* Each time some event arrives on the app, it calls here to report
|
|
|
|
* which event it was. The initial activation of the app is what
|
|
|
|
* starts everything in motion (starting from state 0). At each
|
|
|
|
* state, we assert that we receive the expected event, send the next
|
|
|
|
* event, then update the current_state variable so we do the correct
|
|
|
|
* thing next time.
|
|
|
|
*/
|
|
|
|
|
|
|
|
switch (current_state)
|
|
|
|
{
|
|
|
|
case 0: g_assert_cmpstr (action, ==, "activate");
|
|
|
|
|
|
|
|
/* Let's try another activation... */
|
|
|
|
g_app_info_launch (G_APP_INFO (appinfo), NULL, NULL, NULL);
|
|
|
|
current_state = 1; return; case 1: g_assert_cmpstr (action, ==, "activate");
|
|
|
|
|
|
|
|
|
|
|
|
/* Now let's try opening some files... */
|
|
|
|
{
|
|
|
|
GList *files;
|
|
|
|
|
|
|
|
files = g_list_prepend (NULL, g_file_new_for_uri ("file:///a/b"));
|
|
|
|
files = g_list_append (files, g_file_new_for_uri ("file:///c/d"));
|
|
|
|
g_app_info_launch (G_APP_INFO (appinfo), files, NULL, NULL);
|
|
|
|
g_list_free_full (files, g_object_unref);
|
|
|
|
}
|
|
|
|
current_state = 2; return; case 2: g_assert_cmpstr (action, ==, "open");
|
|
|
|
|
|
|
|
/* Now action activations... */
|
|
|
|
g_desktop_app_info_launch_action (appinfo, "frob", NULL);
|
|
|
|
current_state = 3; return; case 3: g_assert_cmpstr (action, ==, "frob");
|
|
|
|
|
|
|
|
g_desktop_app_info_launch_action (appinfo, "tweak", NULL);
|
|
|
|
current_state = 4; return; case 4: g_assert_cmpstr (action, ==, "tweak");
|
|
|
|
|
|
|
|
g_desktop_app_info_launch_action (appinfo, "twiddle", NULL);
|
|
|
|
current_state = 5; return; case 5: g_assert_cmpstr (action, ==, "twiddle");
|
|
|
|
|
|
|
|
/* Now launch the app with startup notification */
|
|
|
|
{
|
|
|
|
GAppLaunchContext *ctx;
|
|
|
|
|
|
|
|
g_assert (saw_startup_id == FALSE);
|
|
|
|
ctx = g_object_new (test_app_launch_context_get_type (), NULL);
|
|
|
|
g_app_info_launch (G_APP_INFO (appinfo), NULL, ctx, NULL);
|
|
|
|
g_assert (requested_startup_id);
|
|
|
|
requested_startup_id = FALSE;
|
|
|
|
g_object_unref (ctx);
|
|
|
|
}
|
|
|
|
current_state = 6; return; case 6: g_assert_cmpstr (action, ==, "activate"); g_assert (saw_startup_id);
|
|
|
|
saw_startup_id = FALSE;
|
|
|
|
|
|
|
|
/* Now do the same for an action */
|
|
|
|
{
|
|
|
|
GAppLaunchContext *ctx;
|
|
|
|
|
|
|
|
g_assert (saw_startup_id == FALSE);
|
|
|
|
ctx = g_object_new (test_app_launch_context_get_type (), NULL);
|
|
|
|
g_desktop_app_info_launch_action (appinfo, "frob", ctx);
|
|
|
|
g_assert (requested_startup_id);
|
|
|
|
requested_startup_id = FALSE;
|
|
|
|
g_object_unref (ctx);
|
|
|
|
}
|
|
|
|
current_state = 7; return; case 7: g_assert_cmpstr (action, ==, "frob"); g_assert (saw_startup_id);
|
|
|
|
saw_startup_id = FALSE;
|
|
|
|
|
|
|
|
/* Now quit... */
|
|
|
|
g_desktop_app_info_launch_action (appinfo, "quit", NULL);
|
|
|
|
current_state = 8; return; case 8: g_assert_not_reached ();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
|
|
test_application_frob (GSimpleAction *action,
|
|
|
|
GVariant *parameter,
|
|
|
|
gpointer user_data)
|
|
|
|
{
|
|
|
|
g_assert (parameter == NULL);
|
|
|
|
saw_action ("frob");
|
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
|
|
test_application_tweak (GSimpleAction *action,
|
|
|
|
GVariant *parameter,
|
|
|
|
gpointer user_data)
|
|
|
|
{
|
|
|
|
g_assert (parameter == NULL);
|
|
|
|
saw_action ("tweak");
|
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
|
|
test_application_twiddle (GSimpleAction *action,
|
|
|
|
GVariant *parameter,
|
|
|
|
gpointer user_data)
|
|
|
|
{
|
|
|
|
g_assert (parameter == NULL);
|
|
|
|
saw_action ("twiddle");
|
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
|
|
test_application_quit (GSimpleAction *action,
|
|
|
|
GVariant *parameter,
|
|
|
|
gpointer user_data)
|
|
|
|
{
|
|
|
|
GApplication *application = user_data;
|
|
|
|
|
|
|
|
g_application_quit (application);
|
|
|
|
}
|
|
|
|
|
|
|
|
static const GActionEntry app_actions[] = {
|
2020-11-20 20:08:47 +01:00
|
|
|
{ "frob", test_application_frob, NULL, NULL, NULL, { 0 } },
|
|
|
|
{ "tweak", test_application_tweak, NULL, NULL, NULL, { 0 } },
|
|
|
|
{ "twiddle", test_application_twiddle, NULL, NULL, NULL, { 0 } },
|
|
|
|
{ "quit", test_application_quit, NULL, NULL, NULL, { 0 } }
|
2013-06-08 23:31:09 +02:00
|
|
|
};
|
|
|
|
|
|
|
|
static void
|
|
|
|
test_application_activate (GApplication *application)
|
|
|
|
{
|
|
|
|
/* Unbalanced, but that's OK because we will quit() */
|
|
|
|
g_application_hold (application);
|
|
|
|
|
|
|
|
saw_action ("activate");
|
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
|
|
test_application_open (GApplication *application,
|
|
|
|
GFile **files,
|
|
|
|
gint n_files,
|
|
|
|
const gchar *hint)
|
|
|
|
{
|
|
|
|
GFile *f;
|
|
|
|
|
|
|
|
g_assert_cmpstr (hint, ==, "");
|
|
|
|
|
|
|
|
g_assert_cmpint (n_files, ==, 2);
|
|
|
|
f = g_file_new_for_uri ("file:///a/b");
|
|
|
|
g_assert (g_file_equal (files[0], f));
|
|
|
|
g_object_unref (f);
|
|
|
|
f = g_file_new_for_uri ("file:///c/d");
|
|
|
|
g_assert (g_file_equal (files[1], f));
|
|
|
|
g_object_unref (f);
|
|
|
|
|
|
|
|
saw_action ("open");
|
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
|
|
test_application_startup (GApplication *application)
|
|
|
|
{
|
|
|
|
G_APPLICATION_CLASS (test_application_parent_class)
|
|
|
|
->startup (application);
|
|
|
|
|
|
|
|
g_action_map_add_action_entries (G_ACTION_MAP (application), app_actions, G_N_ELEMENTS (app_actions), application);
|
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
|
|
test_application_before_emit (GApplication *application,
|
|
|
|
GVariant *platform_data)
|
|
|
|
{
|
|
|
|
const gchar *startup_id;
|
2022-11-25 19:01:10 +01:00
|
|
|
gsize i;
|
2013-06-08 23:31:09 +02:00
|
|
|
|
|
|
|
g_assert (!saw_startup_id);
|
|
|
|
|
2022-11-25 19:01:10 +01:00
|
|
|
const gchar *startup_id_keys[] = {
|
|
|
|
"desktop-startup-id",
|
|
|
|
"activation-token",
|
|
|
|
NULL,
|
|
|
|
};
|
|
|
|
|
|
|
|
for (i = 0; startup_id_keys[i] != NULL; i++)
|
|
|
|
{
|
|
|
|
if (!g_variant_lookup (platform_data, startup_id_keys[i], "&s", &startup_id))
|
|
|
|
return;
|
|
|
|
|
|
|
|
g_assert_cmpstr (startup_id, ==, "expected startup id");
|
|
|
|
}
|
2013-06-08 23:31:09 +02:00
|
|
|
|
|
|
|
saw_startup_id = TRUE;
|
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
|
|
test_application_init (TestApplication *app)
|
|
|
|
{
|
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
|
|
test_application_class_init (GApplicationClass *class)
|
|
|
|
{
|
|
|
|
class->before_emit = test_application_before_emit;
|
|
|
|
class->startup = test_application_startup;
|
|
|
|
class->activate = test_application_activate;
|
|
|
|
class->open = test_application_open;
|
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
|
|
test_dbus_appinfo (void)
|
|
|
|
{
|
|
|
|
const gchar *argv[] = { "myapp", NULL };
|
|
|
|
TestApplication *app;
|
|
|
|
int status;
|
2018-06-27 10:57:21 +02:00
|
|
|
gchar *desktop_file = NULL;
|
2013-06-08 23:31:09 +02:00
|
|
|
|
2018-06-27 10:57:21 +02:00
|
|
|
desktop_file = g_test_build_filename (G_TEST_DIST,
|
|
|
|
"org.gtk.test.dbusappinfo.desktop",
|
|
|
|
NULL);
|
|
|
|
appinfo = g_desktop_app_info_new_from_filename (desktop_file);
|
2013-06-08 23:31:09 +02:00
|
|
|
g_assert (appinfo != NULL);
|
2018-06-27 10:57:21 +02:00
|
|
|
g_free (desktop_file);
|
2013-06-08 23:31:09 +02:00
|
|
|
|
|
|
|
app = g_object_new (test_application_get_type (),
|
|
|
|
"application-id", "org.gtk.test.dbusappinfo",
|
|
|
|
"flags", G_APPLICATION_HANDLES_OPEN,
|
|
|
|
NULL);
|
|
|
|
status = g_application_run (app, 1, (gchar **) argv);
|
|
|
|
|
|
|
|
g_assert_cmpint (status, ==, 0);
|
|
|
|
g_assert_cmpint (current_state, ==, 8);
|
|
|
|
|
|
|
|
g_object_unref (appinfo);
|
|
|
|
g_object_unref (app);
|
|
|
|
}
|
|
|
|
|
2024-09-19 22:18:16 +02:00
|
|
|
static GType test_flatpak_application_get_type (void);
|
|
|
|
typedef GApplication TestFlatpakApplication;
|
|
|
|
typedef GApplicationClass TestFlatpakApplicationClass;
|
|
|
|
G_DEFINE_TYPE (TestFlatpakApplication, test_flatpak_application, G_TYPE_APPLICATION)
|
|
|
|
|
2019-09-16 16:30:10 +02:00
|
|
|
static void
|
|
|
|
on_flatpak_launch_uris_finish (GObject *object,
|
|
|
|
GAsyncResult *result,
|
|
|
|
gpointer user_data)
|
|
|
|
{
|
|
|
|
GApplication *app = user_data;
|
|
|
|
GError *error = NULL;
|
|
|
|
|
|
|
|
g_app_info_launch_uris_finish (G_APP_INFO (object), result, &error);
|
|
|
|
g_assert_no_error (error);
|
2024-09-19 22:18:16 +02:00
|
|
|
g_assert_true (requested_startup_id);
|
|
|
|
g_assert_true (saw_startup_id);
|
2019-09-16 16:30:10 +02:00
|
|
|
|
|
|
|
g_application_release (app);
|
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
|
|
on_flatpak_activate (GApplication *app,
|
|
|
|
gpointer user_data)
|
|
|
|
{
|
2024-09-19 22:18:16 +02:00
|
|
|
GAppLaunchContext *ctx;
|
2019-09-16 16:30:10 +02:00
|
|
|
GDesktopAppInfo *flatpak_appinfo = user_data;
|
|
|
|
char *uri;
|
|
|
|
GList *uris;
|
|
|
|
|
|
|
|
/* The app will be released in on_flatpak_launch_uris_finish */
|
|
|
|
g_application_hold (app);
|
|
|
|
|
|
|
|
uri = g_filename_to_uri (g_desktop_app_info_get_filename (flatpak_appinfo), NULL, NULL);
|
|
|
|
g_assert_nonnull (uri);
|
|
|
|
uris = g_list_prepend (NULL, uri);
|
2024-09-19 22:18:16 +02:00
|
|
|
ctx = g_object_new (test_app_launch_context_get_type (), NULL);
|
|
|
|
requested_startup_id = FALSE;
|
|
|
|
saw_startup_id = FALSE;
|
|
|
|
g_app_info_launch_uris_async (G_APP_INFO (flatpak_appinfo), uris, ctx,
|
2019-09-16 16:30:10 +02:00
|
|
|
NULL, on_flatpak_launch_uris_finish, app);
|
2024-09-19 22:18:16 +02:00
|
|
|
g_object_unref (ctx);
|
2019-09-16 16:30:10 +02:00
|
|
|
g_list_free (uris);
|
|
|
|
g_free (uri);
|
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
|
|
on_flatpak_open (GApplication *app,
|
|
|
|
GFile **files,
|
|
|
|
gint n_files,
|
|
|
|
const char *hint)
|
|
|
|
{
|
|
|
|
GFile *f;
|
|
|
|
|
|
|
|
g_assert_cmpint (n_files, ==, 1);
|
|
|
|
g_test_message ("on_flatpak_open received file '%s'", g_file_peek_path (files[0]));
|
|
|
|
|
|
|
|
/* The file has been exported via the document portal */
|
|
|
|
f = g_file_new_for_uri ("file:///document-portal/document-id/org.gtk.test.dbusappinfo.flatpak.desktop");
|
|
|
|
g_assert_true (g_file_equal (files[0], f));
|
|
|
|
g_object_unref (f);
|
|
|
|
}
|
|
|
|
|
2024-09-19 22:18:16 +02:00
|
|
|
static void
|
|
|
|
test_flatpak_application_init (TestApplication *app)
|
|
|
|
{
|
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
|
|
test_flatpak_application_class_init (GApplicationClass *class)
|
|
|
|
{
|
|
|
|
class->before_emit = test_application_before_emit;
|
|
|
|
}
|
|
|
|
|
2019-09-16 16:30:10 +02:00
|
|
|
static void
|
|
|
|
test_flatpak_doc_export (void)
|
|
|
|
{
|
|
|
|
const gchar *argv[] = { "myapp", NULL };
|
|
|
|
gchar *desktop_file = NULL;
|
|
|
|
GDesktopAppInfo *flatpak_appinfo;
|
|
|
|
GApplication *app;
|
|
|
|
int status;
|
tests: Move fake-document-portal subprocess inside dbus-appinfo test
For the reasons given in
https://gitlab.gnome.org/GNOME/glib/-/merge_requests/4176#note_2233317,
it’s best to not rely on subprocesses when writing tests. Spawning a
subprocess can go wrong, getting feedback and assertion data from a
subprocess is a pain, and making sure the subprocess is killed properly
at the end of the test is hard to get right.
For tests where we are trying to mock a D-Bus service, it’s much more
reliable to run that service in-process (either in the main thread or in
a separate thread).
So, do that for the `fake-document-portal` former subprocess in the
`dbus-appinfo` test: move it to a worker thread.
This speeds the test up, simplifies the build slightly, and should make
the test run more reliable.
In particular, it provides a pattern for future `fake-*-portal` tests to
be built off. This is particularly useful for more complex portals,
where data needs to be relayed back from the mock portal service to the
unit test to check that the code under test has behaved properly. That’s
a pain to do from a subprocess.
Delete the `org.freedesktop.portal.Documents.service` file because we no
longer need to rely on D-Bus service activation within the test, as
we’re setting up the mock service thread explicitly now.
Signed-off-by: Philip Withnall <pwithnall@gnome.org>
2024-09-27 18:06:40 +02:00
|
|
|
GFakeDocumentPortalThread *thread = NULL;
|
2019-09-16 16:30:10 +02:00
|
|
|
|
|
|
|
g_test_summary ("Test that files launched via Flatpak apps are made available via the document portal.");
|
|
|
|
|
tests: Move fake-document-portal subprocess inside dbus-appinfo test
For the reasons given in
https://gitlab.gnome.org/GNOME/glib/-/merge_requests/4176#note_2233317,
it’s best to not rely on subprocesses when writing tests. Spawning a
subprocess can go wrong, getting feedback and assertion data from a
subprocess is a pain, and making sure the subprocess is killed properly
at the end of the test is hard to get right.
For tests where we are trying to mock a D-Bus service, it’s much more
reliable to run that service in-process (either in the main thread or in
a separate thread).
So, do that for the `fake-document-portal` former subprocess in the
`dbus-appinfo` test: move it to a worker thread.
This speeds the test up, simplifies the build slightly, and should make
the test run more reliable.
In particular, it provides a pattern for future `fake-*-portal` tests to
be built off. This is particularly useful for more complex portals,
where data needs to be relayed back from the mock portal service to the
unit test to check that the code under test has behaved properly. That’s
a pain to do from a subprocess.
Delete the `org.freedesktop.portal.Documents.service` file because we no
longer need to rely on D-Bus service activation within the test, as
we’re setting up the mock service thread explicitly now.
Signed-off-by: Philip Withnall <pwithnall@gnome.org>
2024-09-27 18:06:40 +02:00
|
|
|
/* Run a fake-document-portal */
|
|
|
|
thread = g_fake_document_portal_thread_new (session_bus_get_address ());
|
|
|
|
g_fake_document_portal_thread_run (thread);
|
|
|
|
|
2019-09-16 16:30:10 +02:00
|
|
|
desktop_file = g_test_build_filename (G_TEST_DIST,
|
|
|
|
"org.gtk.test.dbusappinfo.flatpak.desktop",
|
|
|
|
NULL);
|
|
|
|
flatpak_appinfo = g_desktop_app_info_new_from_filename (desktop_file);
|
|
|
|
g_assert_nonnull (flatpak_appinfo);
|
|
|
|
g_free (desktop_file);
|
|
|
|
|
2024-09-19 22:18:16 +02:00
|
|
|
app = g_object_new (test_flatpak_application_get_type (),
|
|
|
|
"application-id", "org.gtk.test.dbusappinfo.flatpak",
|
|
|
|
"flags", G_APPLICATION_HANDLES_OPEN,
|
|
|
|
NULL);
|
2019-09-16 16:30:10 +02:00
|
|
|
g_signal_connect (app, "activate", G_CALLBACK (on_flatpak_activate),
|
|
|
|
flatpak_appinfo);
|
|
|
|
g_signal_connect (app, "open", G_CALLBACK (on_flatpak_open), NULL);
|
|
|
|
|
|
|
|
status = g_application_run (app, 1, (gchar **) argv);
|
|
|
|
g_assert_cmpint (status, ==, 0);
|
|
|
|
|
|
|
|
g_object_unref (app);
|
|
|
|
g_object_unref (flatpak_appinfo);
|
tests: Move fake-document-portal subprocess inside dbus-appinfo test
For the reasons given in
https://gitlab.gnome.org/GNOME/glib/-/merge_requests/4176#note_2233317,
it’s best to not rely on subprocesses when writing tests. Spawning a
subprocess can go wrong, getting feedback and assertion data from a
subprocess is a pain, and making sure the subprocess is killed properly
at the end of the test is hard to get right.
For tests where we are trying to mock a D-Bus service, it’s much more
reliable to run that service in-process (either in the main thread or in
a separate thread).
So, do that for the `fake-document-portal` former subprocess in the
`dbus-appinfo` test: move it to a worker thread.
This speeds the test up, simplifies the build slightly, and should make
the test run more reliable.
In particular, it provides a pattern for future `fake-*-portal` tests to
be built off. This is particularly useful for more complex portals,
where data needs to be relayed back from the mock portal service to the
unit test to check that the code under test has behaved properly. That’s
a pain to do from a subprocess.
Delete the `org.freedesktop.portal.Documents.service` file because we no
longer need to rely on D-Bus service activation within the test, as
we’re setting up the mock service thread explicitly now.
Signed-off-by: Philip Withnall <pwithnall@gnome.org>
2024-09-27 18:06:40 +02:00
|
|
|
g_fake_document_portal_thread_stop (thread);
|
|
|
|
g_clear_object (&thread);
|
2019-09-16 16:30:10 +02:00
|
|
|
}
|
|
|
|
|
2022-09-02 18:56:35 +02:00
|
|
|
static void
|
|
|
|
on_flatpak_launch_invalid_uri_finish (GObject *object,
|
|
|
|
GAsyncResult *result,
|
|
|
|
gpointer user_data)
|
|
|
|
{
|
|
|
|
GApplication *app = user_data;
|
|
|
|
GError *error = NULL;
|
|
|
|
|
|
|
|
g_app_info_launch_uris_finish (G_APP_INFO (object), result, &error);
|
|
|
|
g_assert_no_error (error);
|
2024-09-19 22:18:16 +02:00
|
|
|
g_assert_true (requested_startup_id);
|
|
|
|
g_assert_true (saw_startup_id);
|
2022-09-02 18:56:35 +02:00
|
|
|
|
|
|
|
g_application_release (app);
|
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
|
|
on_flatpak_activate_invalid_uri (GApplication *app,
|
|
|
|
gpointer user_data)
|
|
|
|
{
|
2024-09-19 22:18:16 +02:00
|
|
|
GAppLaunchContext *ctx;
|
2022-09-02 18:56:35 +02:00
|
|
|
GDesktopAppInfo *flatpak_appinfo = user_data;
|
|
|
|
GList *uris;
|
|
|
|
|
|
|
|
/* The app will be released in on_flatpak_launch_uris_finish */
|
|
|
|
g_application_hold (app);
|
|
|
|
|
|
|
|
uris = g_list_prepend (NULL, "file:///hopefully/an/invalid/path.desktop");
|
2024-09-19 22:18:16 +02:00
|
|
|
ctx = g_object_new (test_app_launch_context_get_type (), NULL);
|
|
|
|
requested_startup_id = FALSE;
|
|
|
|
saw_startup_id = FALSE;
|
|
|
|
g_app_info_launch_uris_async (G_APP_INFO (flatpak_appinfo), uris, ctx,
|
2022-09-02 18:56:35 +02:00
|
|
|
NULL, on_flatpak_launch_invalid_uri_finish, app);
|
2024-09-19 22:18:16 +02:00
|
|
|
g_object_unref (ctx);
|
2022-09-02 18:56:35 +02:00
|
|
|
g_list_free (uris);
|
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
|
|
on_flatpak_open_invalid_uri (GApplication *app,
|
|
|
|
GFile **files,
|
|
|
|
gint n_files,
|
|
|
|
const char *hint)
|
|
|
|
{
|
|
|
|
GFile *f;
|
|
|
|
|
|
|
|
g_assert_cmpint (n_files, ==, 1);
|
|
|
|
g_test_message ("on_flatpak_open received file '%s'", g_file_peek_path (files[0]));
|
|
|
|
|
|
|
|
/* The file has been exported via the document portal */
|
|
|
|
f = g_file_new_for_uri ("file:///hopefully/an/invalid/path.desktop");
|
|
|
|
g_assert_true (g_file_equal (files[0], f));
|
|
|
|
g_object_unref (f);
|
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
|
|
test_flatpak_missing_doc_export (void)
|
|
|
|
{
|
|
|
|
const gchar *argv[] = { "myapp", NULL };
|
|
|
|
gchar *desktop_file = NULL;
|
|
|
|
GDesktopAppInfo *flatpak_appinfo;
|
|
|
|
GApplication *app;
|
|
|
|
int status;
|
tests: Move fake-document-portal subprocess inside dbus-appinfo test
For the reasons given in
https://gitlab.gnome.org/GNOME/glib/-/merge_requests/4176#note_2233317,
it’s best to not rely on subprocesses when writing tests. Spawning a
subprocess can go wrong, getting feedback and assertion data from a
subprocess is a pain, and making sure the subprocess is killed properly
at the end of the test is hard to get right.
For tests where we are trying to mock a D-Bus service, it’s much more
reliable to run that service in-process (either in the main thread or in
a separate thread).
So, do that for the `fake-document-portal` former subprocess in the
`dbus-appinfo` test: move it to a worker thread.
This speeds the test up, simplifies the build slightly, and should make
the test run more reliable.
In particular, it provides a pattern for future `fake-*-portal` tests to
be built off. This is particularly useful for more complex portals,
where data needs to be relayed back from the mock portal service to the
unit test to check that the code under test has behaved properly. That’s
a pain to do from a subprocess.
Delete the `org.freedesktop.portal.Documents.service` file because we no
longer need to rely on D-Bus service activation within the test, as
we’re setting up the mock service thread explicitly now.
Signed-off-by: Philip Withnall <pwithnall@gnome.org>
2024-09-27 18:06:40 +02:00
|
|
|
GFakeDocumentPortalThread *thread = NULL;
|
2022-09-02 18:56:35 +02:00
|
|
|
|
|
|
|
g_test_summary ("Test that files launched via Flatpak apps are made available via the document portal.");
|
|
|
|
|
tests: Move fake-document-portal subprocess inside dbus-appinfo test
For the reasons given in
https://gitlab.gnome.org/GNOME/glib/-/merge_requests/4176#note_2233317,
it’s best to not rely on subprocesses when writing tests. Spawning a
subprocess can go wrong, getting feedback and assertion data from a
subprocess is a pain, and making sure the subprocess is killed properly
at the end of the test is hard to get right.
For tests where we are trying to mock a D-Bus service, it’s much more
reliable to run that service in-process (either in the main thread or in
a separate thread).
So, do that for the `fake-document-portal` former subprocess in the
`dbus-appinfo` test: move it to a worker thread.
This speeds the test up, simplifies the build slightly, and should make
the test run more reliable.
In particular, it provides a pattern for future `fake-*-portal` tests to
be built off. This is particularly useful for more complex portals,
where data needs to be relayed back from the mock portal service to the
unit test to check that the code under test has behaved properly. That’s
a pain to do from a subprocess.
Delete the `org.freedesktop.portal.Documents.service` file because we no
longer need to rely on D-Bus service activation within the test, as
we’re setting up the mock service thread explicitly now.
Signed-off-by: Philip Withnall <pwithnall@gnome.org>
2024-09-27 18:06:40 +02:00
|
|
|
/* Run a fake-document-portal */
|
|
|
|
thread = g_fake_document_portal_thread_new (session_bus_get_address ());
|
|
|
|
g_fake_document_portal_thread_run (thread);
|
|
|
|
|
2022-09-02 18:56:35 +02:00
|
|
|
desktop_file = g_test_build_filename (G_TEST_DIST,
|
|
|
|
"org.gtk.test.dbusappinfo.flatpak.desktop",
|
|
|
|
NULL);
|
|
|
|
flatpak_appinfo = g_desktop_app_info_new_from_filename (desktop_file);
|
|
|
|
g_assert_nonnull (flatpak_appinfo);
|
|
|
|
|
2024-09-19 22:18:16 +02:00
|
|
|
app = g_object_new (test_flatpak_application_get_type (),
|
|
|
|
"application-id", "org.gtk.test.dbusappinfo.flatpak",
|
|
|
|
"flags", G_APPLICATION_HANDLES_OPEN,
|
|
|
|
NULL);
|
2022-09-02 18:56:35 +02:00
|
|
|
g_signal_connect (app, "activate", G_CALLBACK (on_flatpak_activate_invalid_uri),
|
|
|
|
flatpak_appinfo);
|
|
|
|
g_signal_connect (app, "open", G_CALLBACK (on_flatpak_open_invalid_uri), NULL);
|
|
|
|
|
|
|
|
status = g_application_run (app, 1, (gchar **) argv);
|
|
|
|
g_assert_cmpint (status, ==, 0);
|
|
|
|
|
|
|
|
g_object_unref (app);
|
|
|
|
g_object_unref (flatpak_appinfo);
|
|
|
|
g_free (desktop_file);
|
tests: Move fake-document-portal subprocess inside dbus-appinfo test
For the reasons given in
https://gitlab.gnome.org/GNOME/glib/-/merge_requests/4176#note_2233317,
it’s best to not rely on subprocesses when writing tests. Spawning a
subprocess can go wrong, getting feedback and assertion data from a
subprocess is a pain, and making sure the subprocess is killed properly
at the end of the test is hard to get right.
For tests where we are trying to mock a D-Bus service, it’s much more
reliable to run that service in-process (either in the main thread or in
a separate thread).
So, do that for the `fake-document-portal` former subprocess in the
`dbus-appinfo` test: move it to a worker thread.
This speeds the test up, simplifies the build slightly, and should make
the test run more reliable.
In particular, it provides a pattern for future `fake-*-portal` tests to
be built off. This is particularly useful for more complex portals,
where data needs to be relayed back from the mock portal service to the
unit test to check that the code under test has behaved properly. That’s
a pain to do from a subprocess.
Delete the `org.freedesktop.portal.Documents.service` file because we no
longer need to rely on D-Bus service activation within the test, as
we’re setting up the mock service thread explicitly now.
Signed-off-by: Philip Withnall <pwithnall@gnome.org>
2024-09-27 18:06:40 +02:00
|
|
|
g_fake_document_portal_thread_stop (thread);
|
|
|
|
g_clear_object (&thread);
|
2022-09-02 18:56:35 +02:00
|
|
|
}
|
|
|
|
|
2024-09-24 14:12:15 +02:00
|
|
|
static void
|
|
|
|
check_portal_openuri_call (const char *expected_uri,
|
|
|
|
GFakeDesktopPortalThread *thread)
|
|
|
|
{
|
|
|
|
const char *activation_token = NULL;
|
|
|
|
GFile *expected_file = NULL;
|
|
|
|
GFile *file = NULL;
|
|
|
|
const char *uri = NULL;
|
|
|
|
|
|
|
|
activation_token = g_fake_desktop_portal_thread_get_last_request_activation_token (thread);
|
|
|
|
uri = g_fake_desktop_portal_thread_get_last_request_uri (thread);
|
|
|
|
|
|
|
|
g_assert_cmpstr (activation_token, ==, "expected startup id");
|
|
|
|
g_assert_nonnull (uri);
|
|
|
|
|
|
|
|
expected_file = g_file_new_for_uri (expected_uri);
|
|
|
|
file = g_file_new_for_uri (uri);
|
|
|
|
g_assert_true (g_file_equal (expected_file, file));
|
|
|
|
|
|
|
|
g_object_unref (file);
|
|
|
|
g_object_unref (expected_file);
|
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
|
|
test_portal_open_file (void)
|
|
|
|
{
|
|
|
|
GAppLaunchContext *ctx;
|
|
|
|
GError *error = NULL;
|
|
|
|
char *uri;
|
|
|
|
GFakeDesktopPortalThread *thread = NULL;
|
|
|
|
|
|
|
|
/* Run a fake-desktop-portal */
|
|
|
|
thread = g_fake_desktop_portal_thread_new (session_bus_get_address ());
|
|
|
|
g_fake_desktop_portal_thread_run (thread);
|
|
|
|
|
|
|
|
uri = g_filename_to_uri (g_test_get_filename (G_TEST_DIST,
|
|
|
|
"org.gtk.test.dbusappinfo.flatpak.desktop",
|
|
|
|
NULL),
|
|
|
|
NULL,
|
|
|
|
NULL);
|
|
|
|
|
|
|
|
ctx = g_object_new (test_app_launch_context_get_type (), NULL);
|
|
|
|
|
|
|
|
requested_startup_id = FALSE;
|
|
|
|
|
|
|
|
g_app_info_launch_default_for_uri (uri, ctx, &error);
|
|
|
|
|
|
|
|
g_assert_no_error (error);
|
|
|
|
g_assert_true (requested_startup_id);
|
|
|
|
|
|
|
|
g_fake_desktop_portal_thread_stop (thread);
|
|
|
|
check_portal_openuri_call (uri, thread);
|
|
|
|
|
|
|
|
g_clear_object (&ctx);
|
|
|
|
g_clear_object (&thread);
|
|
|
|
g_clear_pointer (&uri, g_free);
|
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
|
|
test_portal_open_uri (void)
|
|
|
|
{
|
|
|
|
GAppLaunchContext *ctx;
|
|
|
|
GError *error = NULL;
|
|
|
|
const char *uri = "http://example.com";
|
|
|
|
GFakeDesktopPortalThread *thread = NULL;
|
|
|
|
|
|
|
|
/* Run a fake-desktop-portal */
|
|
|
|
thread = g_fake_desktop_portal_thread_new (session_bus_get_address ());
|
|
|
|
g_fake_desktop_portal_thread_run (thread);
|
|
|
|
|
|
|
|
ctx = g_object_new (test_app_launch_context_get_type (), NULL);
|
|
|
|
|
|
|
|
requested_startup_id = FALSE;
|
|
|
|
|
|
|
|
g_app_info_launch_default_for_uri (uri, ctx, &error);
|
|
|
|
|
|
|
|
g_assert_no_error (error);
|
|
|
|
g_assert_true (requested_startup_id);
|
|
|
|
|
|
|
|
g_fake_desktop_portal_thread_stop (thread);
|
|
|
|
check_portal_openuri_call (uri, thread);
|
|
|
|
|
|
|
|
g_clear_object (&ctx);
|
|
|
|
g_clear_object (&thread);
|
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
|
|
on_launch_default_for_uri_finished (GObject *object,
|
|
|
|
GAsyncResult *result,
|
|
|
|
gpointer user_data)
|
|
|
|
{
|
|
|
|
GError *error = NULL;
|
|
|
|
gboolean *called = user_data;
|
|
|
|
|
|
|
|
g_app_info_launch_default_for_uri_finish (result, &error);
|
|
|
|
g_assert_no_error (error);
|
|
|
|
|
|
|
|
*called = TRUE;
|
|
|
|
|
|
|
|
g_main_context_wakeup (NULL);
|
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
|
|
test_portal_open_file_async (void)
|
|
|
|
{
|
|
|
|
GAppLaunchContext *ctx;
|
|
|
|
gboolean called = FALSE;
|
|
|
|
char *uri;
|
|
|
|
GFakeDesktopPortalThread *thread = NULL;
|
|
|
|
|
|
|
|
/* Run a fake-desktop-portal */
|
|
|
|
thread = g_fake_desktop_portal_thread_new (session_bus_get_address ());
|
|
|
|
g_fake_desktop_portal_thread_run (thread);
|
|
|
|
|
|
|
|
uri = g_filename_to_uri (g_test_get_filename (G_TEST_DIST,
|
|
|
|
"org.gtk.test.dbusappinfo.flatpak.desktop",
|
|
|
|
NULL),
|
|
|
|
NULL,
|
|
|
|
NULL);
|
|
|
|
|
|
|
|
ctx = g_object_new (test_app_launch_context_get_type (), NULL);
|
|
|
|
|
|
|
|
requested_startup_id = FALSE;
|
|
|
|
|
|
|
|
g_app_info_launch_default_for_uri_async (uri, ctx,
|
|
|
|
NULL, on_launch_default_for_uri_finished, &called);
|
|
|
|
|
|
|
|
while (!called)
|
|
|
|
g_main_context_iteration (NULL, TRUE);
|
|
|
|
|
|
|
|
g_assert_true (requested_startup_id);
|
|
|
|
|
|
|
|
g_fake_desktop_portal_thread_stop (thread);
|
|
|
|
check_portal_openuri_call (uri, thread);
|
|
|
|
|
|
|
|
g_clear_pointer (&uri, g_free);
|
|
|
|
g_clear_object (&ctx);
|
|
|
|
g_clear_object (&thread);
|
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
|
|
test_portal_open_uri_async (void)
|
|
|
|
{
|
|
|
|
GAppLaunchContext *ctx;
|
|
|
|
gboolean called = FALSE;
|
|
|
|
const char *uri = "http://example.com";
|
|
|
|
GFakeDesktopPortalThread *thread = NULL;
|
|
|
|
|
|
|
|
/* Run a fake-desktop-portal */
|
|
|
|
thread = g_fake_desktop_portal_thread_new (session_bus_get_address ());
|
|
|
|
g_fake_desktop_portal_thread_run (thread);
|
|
|
|
|
|
|
|
ctx = g_object_new (test_app_launch_context_get_type (), NULL);
|
|
|
|
|
|
|
|
requested_startup_id = FALSE;
|
|
|
|
|
|
|
|
g_app_info_launch_default_for_uri_async (uri, ctx,
|
|
|
|
NULL, on_launch_default_for_uri_finished, &called);
|
|
|
|
|
|
|
|
while (!called)
|
|
|
|
g_main_context_iteration (NULL, TRUE);
|
|
|
|
|
|
|
|
g_assert_true (requested_startup_id);
|
|
|
|
|
|
|
|
g_fake_desktop_portal_thread_stop (thread);
|
|
|
|
check_portal_openuri_call (uri, thread);
|
|
|
|
|
|
|
|
g_clear_object (&ctx);
|
|
|
|
g_clear_object (&thread);
|
|
|
|
}
|
|
|
|
|
2013-06-08 23:31:09 +02:00
|
|
|
int
|
|
|
|
main (int argc, char **argv)
|
|
|
|
{
|
2024-09-27 18:12:52 +02:00
|
|
|
g_test_init (&argc, &argv, G_TEST_OPTION_ISOLATE_DIRS, NULL);
|
2013-06-08 23:31:09 +02:00
|
|
|
|
2024-09-24 14:12:15 +02:00
|
|
|
g_setenv ("GIO_USE_PORTALS", "1", TRUE);
|
|
|
|
|
2013-06-08 23:31:09 +02:00
|
|
|
g_test_add_func ("/appinfo/dbusappinfo", test_dbus_appinfo);
|
2019-09-16 16:30:10 +02:00
|
|
|
g_test_add_func ("/appinfo/flatpak-doc-export", test_flatpak_doc_export);
|
2022-09-02 18:56:35 +02:00
|
|
|
g_test_add_func ("/appinfo/flatpak-missing-doc-export", test_flatpak_missing_doc_export);
|
2024-09-24 14:12:15 +02:00
|
|
|
g_test_add_func ("/appinfo/portal-open-file", test_portal_open_file);
|
|
|
|
g_test_add_func ("/appinfo/portal-open-uri", test_portal_open_uri);
|
|
|
|
g_test_add_func ("/appinfo/portal-open-file-async", test_portal_open_file_async);
|
|
|
|
g_test_add_func ("/appinfo/portal-open-uri-async", test_portal_open_uri_async);
|
2019-09-16 16:30:10 +02:00
|
|
|
|
2019-12-17 10:33:04 +01:00
|
|
|
return session_bus_run ();
|
2013-06-08 23:31:09 +02:00
|
|
|
}
|