diff --git a/docs/gettingstarted.md b/docs/gettingstarted.md index 9383d0755ea49b083febff351e99939212ff72fb..a7c68e706da45d50f5c96657a3faf020dca2ed57 100644 --- a/docs/gettingstarted.md +++ b/docs/gettingstarted.md @@ -125,6 +125,35 @@ gdbus call --session -d org.gnome.SettingsDaemon.Rfkill \ -m org.freedesktop.DBus.Mock.SetAirplaneMode true ``` +### Integration tests + +#### Running with DBus mocks + +We have some tests checking integration with system services like +ModemManager using python-dbusmock. You can run them using + +```sh +_build/tests/integration/run-pytest -v -s tests/integration/test_dbus.py +``` + +If you want to inspect phosh's log output use + +```sh +SAVE_TEST_LOGS=1 _build-test/tests/integration/run-pytest -s tests/integration/test_dbus.py +``` + +and `stderr` and `stdout` will be written into `log.stderr` and +`log.stdout` in the current directory. + +#### Running the Screenshot Tests + +One testcase brings up different parts of the shell and takes screenshots from them +to ease finding visual regressions. You can run them locally via + +```sh +PHOSH_TEST_TYPE=doesnotmatter _build-test/tests/test-take-screenshots +``` + ### GTK Inspector Since phosh is a GTK application you can use diff --git a/src/ambient.c b/src/ambient.c index efbc85bc3053707ce69143fe54605f6a5adacc5d..6fc839275b194cd9256e01a684afc125dbda4f09 100644 --- a/src/ambient.c +++ b/src/ambient.c @@ -318,10 +318,13 @@ on_ambient_released (GObject *source_object, GAsyncResult *res, gpointer user_da g_return_if_fail (proxy == PHOSH_DBUS_SENSOR_PROXY (self->sensor_proxy_manager)); success = phosh_dbus_sensor_proxy_call_release_light_finish (proxy, res, &err); - if (success) + if (success) { g_debug ("Released ambient light sensor"); - else + } else { + if (g_error_matches (err, G_IO_ERROR, G_IO_ERROR_CANCELLED)) + return; g_warning ("Failed to release ambient sensor: %s", err->message); + } self->claimed--; update_auto_brightness_enabled (self); diff --git a/tests/test-take-screenshots.c b/tests/test-take-screenshots.c index d5bd5a23ffaf40dfa359c220f6c95e7db8d9985a..72269cbf4aec573748938b317622c53c0d8ed763 100644 --- a/tests/test-take-screenshots.c +++ b/tests/test-take-screenshots.c @@ -1,5 +1,6 @@ /* * Copyright (C) 2021 Purism SPC + * 2025 Phosh.mobi e.V. * * SPDX-License-Identifier: GPL-3.0-or-later * @@ -28,6 +29,9 @@ #define WAIT_TIMEOUT 30000 +uint num_toplevels; + + static void take_screenshot (const char *what, int num, const char *where) { @@ -244,10 +248,10 @@ on_osd_finish (GObject *source_object, static GPid -run_plugin_prefs (void) +run_plugin_prefs (const char *arg) { g_autoptr (GError) err = NULL; - const char *argv[] = { TEST_TOOLS "/plugin-prefs", NULL }; + const char *argv[] = { TEST_TOOLS "/plugin-prefs", arg, NULL }; gboolean ret; GPid pid; @@ -260,33 +264,123 @@ run_plugin_prefs (void) } +static gboolean +wait_for_num_toplevels (GMainLoop *loop, + uint n, + uint timeout, + GSourceFunc callback, + gpointer userdata) +{ + gboolean found = FALSE; + uint sleep = 100; + + while (timeout > 0) { + if (callback) + (callback) (userdata); + + if (num_toplevels == n) { + found = TRUE; + break; + } + wait_a_bit (loop, sleep); + timeout -= sleep; + } + + return found; +} + + +typedef struct { + struct zwp_virtual_keyboard_v1 *keyboard; + uint modifiers; + uint key; +} PhoshTestKbdShortcut; + + +static gboolean +send_kbd_shortcut_cb (gpointer user_data) +{ + PhoshTestKbdShortcut *shortcut = user_data; + g_autoptr (GTimer) timer = g_timer_new (); + + if (shortcut->modifiers) + phosh_test_keyboard_press_modifiers (shortcut->keyboard, shortcut->modifiers); + + phosh_test_keyboard_press_keys (shortcut->keyboard, timer, shortcut->key, NULL); + + if (shortcut->modifiers) + phosh_test_keyboard_release_modifiers (shortcut->keyboard); + + return TRUE; +} + + +static void +screenshot_plugin_pref (GMainLoop *loop, + const char *what, + const char *where, + int num, + struct zwp_virtual_keyboard_v1 *keyboard, + guint key) +{ + g_test_message ("Screenshotting '%s'", what); + g_debug ("Waiting for prefs app…"); + g_assert (wait_for_num_toplevels (loop, 1, 5000, NULL, NULL)); + + g_debug ("Opening prefs…"); + g_assert (wait_for_num_toplevels (loop, 2, 5000, send_kbd_shortcut_cb, + &(PhoshTestKbdShortcut){ keyboard, KEY_LEFTCTRL, key })); + g_debug ("Closing prefs…"); + take_screenshot (what, num++, where); + + g_assert (wait_for_num_toplevels (loop, 1, 5000, send_kbd_shortcut_cb, + &(PhoshTestKbdShortcut){ keyboard, 0, KEY_ESC })); +} + + static int -screenshot_plugin_prefs (GMainLoop *loop, - const char *what, - int num, - struct zwp_virtual_keyboard_v1 *keyboard, - GTimer *timer, - PhoshTestWaitForShellState *waiter) +screenshot_lockscreen_plugin_prefs (GMainLoop *loop, + const char *what, + int num, + struct zwp_virtual_keyboard_v1 *keyboard, + PhoshTestWaitForShellState *waiter) { GPid pid; - pid = run_plugin_prefs (); + pid = run_plugin_prefs ("-l"); /* Wait for overview to close */ phosh_test_wait_for_shell_state_wait (waiter, PHOSH_STATE_OVERVIEW, FALSE, WAIT_TIMEOUT); - /* Give app time to start */ - wait_a_bit (loop, 2000); - phosh_test_keyboard_press_modifiers (keyboard, KEY_LEFTCTRL); - phosh_test_keyboard_press_keys (keyboard, timer, KEY_T, NULL); - phosh_test_keyboard_release_modifiers (keyboard); - wait_a_bit (loop, 1000); - take_screenshot (what, num++, "plugin-prefs-ticket-box"); - phosh_test_keyboard_press_keys (keyboard, timer, KEY_ESC, NULL); - wait_a_bit (loop, 500); - phosh_test_keyboard_press_modifiers (keyboard, KEY_LEFTCTRL); - phosh_test_keyboard_press_keys (keyboard, timer, KEY_E, NULL); - phosh_test_keyboard_release_modifiers (keyboard); - wait_a_bit (loop, 500); - take_screenshot (what, num++, "plugin-prefs-emergncy-info"); + + screenshot_plugin_pref (loop, what, "plugin-prefs-ticket-box", num++, keyboard, KEY_T); + screenshot_plugin_pref (loop, what, "plugin-prefs-emergency-info", num++, keyboard, KEY_E); + screenshot_plugin_pref (loop, what, "plugin-prefs-upcoming-events", num++, keyboard, KEY_U); + + g_assert_no_errno (kill (pid, SIGTERM)); + g_spawn_close_pid (pid); + + /* wait for app to quit and overview to be visible again */ + phosh_test_wait_for_shell_state_wait (waiter, PHOSH_STATE_OVERVIEW, TRUE, WAIT_TIMEOUT); + + return num; +} + + +static int +screenshot_quick_setting_plugin_prefs (GMainLoop *loop, + const char *what, + int num, + struct zwp_virtual_keyboard_v1 *keyboard, + PhoshTestWaitForShellState *waiter) +{ + GPid pid; + + pid = run_plugin_prefs ("-q"); + /* Wait for overview to close */ + phosh_test_wait_for_shell_state_wait (waiter, PHOSH_STATE_OVERVIEW, FALSE, WAIT_TIMEOUT); + + screenshot_plugin_pref (loop, what, "plugin-prefs-caffeine", num++, keyboard, KEY_C); + screenshot_plugin_pref (loop, what, "plugin-prefs-pomodoro", num++, keyboard, KEY_P); + g_assert_no_errno (kill (pid, SIGTERM)); g_spawn_close_pid (pid); @@ -549,6 +643,14 @@ screenshot_emergency_calls (GMainLoop *loop, } +static void +on_num_toplevels_changed (PhoshToplevelManager *toplevel_manager) +{ + num_toplevels = phosh_toplevel_manager_get_num_toplevels (toplevel_manager); + g_debug ("Num toplevels: %d", num_toplevels); +} + + static void test_take_screenshots (PhoshTestFullShellFixture *fixture, gconstpointer unused) { @@ -563,7 +665,8 @@ test_take_screenshots (PhoshTestFullShellFixture *fixture, gconstpointer unused) g_autoptr (PhoshTestMprisMock) mpris_mock = NULL; g_autoptr (GError) err = NULL; g_autoptr (PhoshTestWaitForShellState) waiter = NULL; - + PhoshShell *shell; + PhoshToplevelManager *toplevel_manager; const char *argv[] = { TEST_TOOLS "/app-buttons", NULL }; GPid pid; int i = 1; @@ -573,7 +676,14 @@ test_take_screenshots (PhoshTestFullShellFixture *fixture, gconstpointer unused) g_assert_nonnull (g_async_queue_timeout_pop (fixture->queue, POP_TIMEOUT)); loop = g_main_loop_new (context, FALSE); - waiter = phosh_test_wait_for_shell_state_new (phosh_shell_get_default ()); + shell = phosh_shell_get_default (); + waiter = phosh_test_wait_for_shell_state_new (shell); + + toplevel_manager = phosh_shell_get_toplevel_manager (shell); + g_signal_connect (toplevel_manager, + "notify::num-toplevels", + G_CALLBACK (on_num_toplevels_changed), + &num_toplevels); /* Give overview animation time to finish */ phosh_test_wait_for_shell_state_wait (waiter, PHOSH_STATE_SETTINGS, FALSE, WAIT_TIMEOUT); @@ -604,7 +714,8 @@ test_take_screenshots (PhoshTestFullShellFixture *fixture, gconstpointer unused) kill (pid, SIGTERM); g_spawn_close_pid (pid); - i = screenshot_plugin_prefs (loop, what, i, keyboard, timer, waiter); + i = screenshot_lockscreen_plugin_prefs (loop, what, i, keyboard, waiter); + i = screenshot_quick_setting_plugin_prefs (loop, what, i, keyboard, waiter); show_run_command_dialog (loop, keyboard, timer, waiter, TRUE); take_screenshot (what, i++, "run-command"); diff --git a/tools/plugin-prefs-standalone.c b/tools/plugin-prefs-standalone.c index 4e9c8a3983e87e717adc33e64bcc6c4e41d017f6..5117c985d6dc428fcd07039e7eba643e44adce6e 100644 --- a/tools/plugin-prefs-standalone.c +++ b/tools/plugin-prefs-standalone.c @@ -1,13 +1,13 @@ /* - * Copyright (C) 2022 Phosh.mobi e.V. + * Copyright (C) 2022-2025 Phosh.mobi e.V. * * SPDX-License-Identifier: GPL-3.0-or-later * * Author: Guido Günther * - * BUILDDIR $ ./tools/run_tool ./tools/plugin-prefs-standalone + * BUILDDIR $ ./tools/run_tool ./tools/plugin-prefs * - * plugin-prefs-standalone: A simple wrapper to look at plugin preferenes + * plugin-prefs-standalone: A simple wrapper to look at plugin preferences */ #include "phosh-config.h" @@ -18,6 +18,7 @@ #include #include +#include typedef struct _PluginInfo { @@ -130,6 +131,18 @@ on_app_activated (GtkApplication *app) } +static gboolean +on_sigterm (gpointer user_data) +{ + GApplication *app = user_data; + + g_debug ("Got SIGTERM, quitting"); + g_application_quit (app); + + return G_SOURCE_REMOVE; +} + + static GActionEntry entries[] = { { .name = "show-prefs", .parameter_type = "s", .activate = on_activated }, @@ -142,8 +155,10 @@ main (int argc, char *argv[]) g_autoptr (AdwApplication) app = NULL; g_autoptr (GOptionContext) opt_context = NULL; g_autoptr (GError) err = NULL; - gboolean quick_settings = FALSE; + gboolean quick_settings = FALSE, lock_screen = FALSE; const GOptionEntry options [] = { + {"lock-screen", 'l', 0, G_OPTION_ARG_NONE, &lock_screen, + "Load quick setting plugin prefs", NULL}, {"quick-settings", 'q', 0, G_OPTION_ARG_NONE, &quick_settings, "Load quick setting plugin prefs", NULL}, { NULL, 0, 0, G_OPTION_ARG_NONE, NULL, NULL, NULL } @@ -159,6 +174,12 @@ main (int argc, char *argv[]) g_warning ("%s", err->message); return 1; } + + if (lock_screen && quick_settings) { + g_warning ("Can show either lock screen or quick setting plugins"); + return 1; + } + plugin_info = &plugin_infos[quick_settings ? 1 : 0]; app = g_object_new (ADW_TYPE_APPLICATION, @@ -169,6 +190,8 @@ main (int argc, char *argv[]) entries, G_N_ELEMENTS (entries), app); + + g_unix_signal_add (SIGTERM, on_sigterm, app); g_application_run (G_APPLICATION (app), argc, argv); return EXIT_SUCCESS;