[gnome-settings-daemon] Add support for plugin tests
- From: Bastien Nocera <hadess src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [gnome-settings-daemon] Add support for plugin tests
- Date: Mon, 7 Jan 2013 09:43:04 +0000 (UTC)
commit 2fbb4040219bf564ac4dc9e2ec383c1522d0445b
Author: Martin Pitt <martinpitt gnome org>
Date: Fri Jan 4 17:33:08 2013 +0100
Add support for plugin tests
Add a GSDTestCase Python class (tests/gsdtestcase.py) which provides
functionality for writing daemon and plugin tests:
* Launch temporary private session and system D-BUSes to avoid disturbing
the currently running system and being able to use mock D-BUS services.
* Run a minimal gnome-session to ensure plugins can check the session idle
status, register to the session, etc.
* Configure temporary local XDG directories to avoid disturbing the user's
real settings and files.
* Run a mock notification daemon to avoid showing notifications produced
by test cases, using python-dbusmock.
(http://pypi.python.org/pypi/python-dbusmock)
* Provide API to start/stop a mock logind, using python-dbusmock.
* Provide API to reste the session idle timer, using a small "shiftkey"
helper program that sends a "left shift key" event through XTest.
If any of the required dependencies (gnome-session, dbusmock, pygobject) is
not present, it exits with an error message and exit code 0, to avoid
breaking tests in minimal build environments.
https://bugzilla.gnome.org/show_bug.cgi?id=685951
.gitignore | 1 +
Makefile.am | 1 +
configure.ac | 9 +++
tests/Makefile.am | 11 +++
tests/dummy.session | 5 ++
tests/dummyapp.desktop | 5 ++
tests/gsdtestcase.py | 188 ++++++++++++++++++++++++++++++++++++++++++++++++
tests/shiftkey.c | 56 ++++++++++++++
8 files changed, 276 insertions(+), 0 deletions(-)
---
diff --git a/.gitignore b/.gitignore
index ed51335..5fa6217 100644
--- a/.gitignore
+++ b/.gitignore
@@ -56,3 +56,4 @@ plugins/media-keys/test-media-window
plugins/mouse/gsd-locate-pointer
plugins/xrandr/gsd-xrandr-manager-glue.h
plugins/xsettings/test-gtk-modules
+tests/shiftkey
diff --git a/Makefile.am b/Makefile.am
index 6bb3d58..e7ae030 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -5,6 +5,7 @@ SUBDIRS = \
plugins \
data \
po \
+ tests \
$(NULL)
if ENABLE_MAN
diff --git a/configure.ac b/configure.ac
index f7470ce..722c271 100644
--- a/configure.ac
+++ b/configure.ac
@@ -144,6 +144,14 @@ dnl ---------------------------------------------------------------------------
PKG_CHECK_MODULES(COMMON, x11 kbproto xi)
dnl ---------------------------------------------------------------------------
+dnl - XTest
+dnl ---------------------------------------------------------------------------
+
+PKG_CHECK_MODULES(XTEST, x11 xtst)
+AC_SUBST(XTEST_CFLAGS)
+AC_SUBST(XTEST_LIBS)
+
+dnl ---------------------------------------------------------------------------
dnl - background
dnl ---------------------------------------------------------------------------
@@ -517,6 +525,7 @@ data/org.gnome.settings-daemon.peripherals.wacom.gschema.xml.in
data/org.gnome.settings-daemon.plugins.print-notifications.gschema.xml.in
po/Makefile.in
man/Makefile
+tests/Makefile
])
dnl ---------------------------------------------------------------------------
diff --git a/tests/Makefile.am b/tests/Makefile.am
new file mode 100644
index 0000000..da78a69
--- /dev/null
+++ b/tests/Makefile.am
@@ -0,0 +1,11 @@
+noinst_PROGRAMS = shiftkey
+
+shiftkey_SOURCES = shiftkey.c
+shiftkey_CFLAGS = -I$(top_builddir) $(XTEST_CFLAGS)
+shiftkey_LDADD = $(XTEST_LIBS)
+
+EXTRA_DIST = \
+ gsdtestcase.py \
+ dummy.session \
+ dummyapp.desktop \
+ $(NULL)
diff --git a/tests/dummy.session b/tests/dummy.session
new file mode 100644
index 0000000..96a1aa8
--- /dev/null
+++ b/tests/dummy.session
@@ -0,0 +1,5 @@
+[GNOME Session]
+Name=dummy
+RequiredComponents=dummyapp
+DesktopName=dummy
+
diff --git a/tests/dummyapp.desktop b/tests/dummyapp.desktop
new file mode 100644
index 0000000..3bb53b2
--- /dev/null
+++ b/tests/dummyapp.desktop
@@ -0,0 +1,5 @@
+[Desktop Entry]
+Name=dummyapp
+Type=Application
+Exec=sleep 3600
+
diff --git a/tests/gsdtestcase.py b/tests/gsdtestcase.py
new file mode 100644
index 0000000..c2bedf8
--- /dev/null
+++ b/tests/gsdtestcase.py
@@ -0,0 +1,188 @@
+'''GNOME settings daemon test base class'''
+
+__author__ = 'Martin Pitt <martin pitt ubuntu com>'
+__copyright__ = '(C) 2013 Canonical Ltd.'
+__license__ = 'GPL v2 or later'
+
+import subprocess
+import time
+import os
+import os.path
+import tempfile
+import fcntl
+import shutil
+import sys
+from glob import glob
+
+try:
+ import dbusmock
+except ImportError:
+ sys.stderr.write('You need python-dbusmock (http://pypi.python.org/pypi/python-dbusmock) for this test suite.\n')
+ sys.exit(0)
+
+try:
+ from gi.repository import Gio
+except ImportError:
+ sys.stderr.write('You need pygobject and the Gio GIR for this test suite.\n')
+ sys.exit(0)
+
+if subprocess.call(['which', 'gnome-session'], stdout=subprocess.PIPE) != 0:
+ sys.stderr.write('You need gnome-session for this test suite.\n')
+ sys.exit(0)
+
+
+top_builddir = os.environ.get('TOP_BUILDDIR',
+ os.path.dirname(os.path.dirname(os.path.abspath(__file__))))
+
+
+def set_nonblock(fd):
+ '''Set a file object to non-blocking'''
+
+ flags = fcntl.fcntl(fd, fcntl.F_GETFL)
+ fcntl.fcntl(fd, fcntl.F_SETFL, flags | os.O_NONBLOCK)
+
+
+class GSDTestCase(dbusmock.DBusTestCase):
+ '''Base class for settings daemon tests
+
+ This redirects the XDG directories to temporary directories, and runs local
+ session and system D-BUSes with a minimal GNOME session and a mock
+ notification daemon. It also provides common functionality for plugin
+ tests.
+ '''
+ @classmethod
+ def setUpClass(klass):
+ os.environ['GIO_USE_VFS'] = 'local'
+ # we do some string checks, disable translations
+ os.environ['LC_MESSAGES'] = 'C'
+ klass.workdir = tempfile.mkdtemp(prefix='gsd-power-test')
+
+ # tell dconf and friends to use our config/runtime directories
+ os.environ['XDG_CONFIG_HOME'] = os.path.join(klass.workdir, 'config')
+ os.environ['XDG_DATA_HOME'] = os.path.join(klass.workdir, 'data')
+ os.environ['XDG_RUNTIME_DIR'] = os.path.join(klass.workdir, 'runtime')
+
+ # work around https://bugzilla.gnome.org/show_bug.cgi?id=689136
+ os.makedirs(os.path.join(os.environ['XDG_CONFIG_HOME'], 'dconf'))
+
+ klass.start_system_bus()
+ klass.start_session_bus()
+ klass.system_bus_con = klass.get_dbus(True)
+ klass.session_bus_con = klass.get_dbus(False)
+
+ # we never want to cause notifications on the actual GUI
+ klass.p_notify = klass.spawn_server_template(
+ 'notification_daemon', {}, stdout=subprocess.PIPE)[0]
+ set_nonblock(klass.p_notify.stdout)
+
+ klass.start_session()
+
+ klass.settings_session = Gio.Settings('org.gnome.desktop.session')
+
+ @classmethod
+ def tearDownClass(klass):
+ klass.stop_session()
+ dbusmock.DBusTestCase.tearDownClass()
+ shutil.rmtree(klass.workdir)
+
+ def run(self, result=None):
+ '''Show log files on failed tests
+
+ If the environment variable $SHELL_ON_FAIL is set, this runs bash in
+ the work directory; exit the shell to continue the tests. Otherwise it
+ shows all log files.
+ '''
+ if result:
+ orig_err_fail = result.errors + result.failures
+ super(GSDTestCase, self).run(result)
+ if result and result.errors + result.failures > orig_err_fail:
+ if 'SHELL_ON_FAIL' in os.environ:
+ subprocess.call(['bash', '-i'], cwd=self.workdir)
+ else:
+ for log_file in glob(os.path.join(self.workdir, '*.log')):
+ with open(log_file) as f:
+ print('\n----- %s -----\n%s\n------\n'
+ % (log_file, f.read()))
+
+ @classmethod
+ def start_session(klass):
+ '''Start minimal GNOME session'''
+
+ # create dummy session type and component
+ d = os.path.join(klass.workdir, 'config', 'gnome-session', 'sessions')
+ if not os.path.isdir(d):
+ os.makedirs(d)
+ shutil.copy(os.path.join(os.path.dirname(__file__), 'dummy.session'), d)
+
+ d = os.path.join(klass.workdir, 'data', 'applications')
+ if not os.path.isdir(d):
+ os.makedirs(d)
+ shutil.copy(os.path.join(os.path.dirname(__file__), 'dummyapp.desktop'), d)
+
+ klass.session_log = open(os.path.join(klass.workdir, 'gnome-session.log'), 'wb')
+ klass.session = subprocess.Popen(['gnome-session', '-f',
+ '-a', os.path.join(klass.workdir, 'autostart'),
+ '--session=dummy', '--debug'],
+ stdout=klass.session_log,
+ stderr=subprocess.STDOUT)
+
+ # wait until the daemon is on the bus
+ try:
+ klass.wait_for_bus_object('org.gnome.SessionManager',
+ '/org/gnome/SessionManager')
+ except:
+ # on failure, print log
+ with open(klass.session_log.name) as f:
+ print('----- session log -----\n%s\n------' % f.read())
+ raise
+
+ klass.obj_session_mgr = klass.session_bus_con.get_object(
+ 'org.gnome.SessionManager', '/org/gnome/SessionManager')
+
+ # give g-session some time to lazily initialize idle timers, etc.
+ time.sleep(3)
+
+ @classmethod
+ def stop_session(klass):
+ '''Stop GNOME session'''
+
+ assert klass.session
+ klass.session.terminate()
+ klass.session.wait()
+
+ klass.session_log.flush()
+ klass.session_log.close()
+
+ def start_logind(self):
+ '''start mock logind'''
+
+ self.logind = self.spawn_server('org.freedesktop.login1',
+ '/org/freedesktop/login1',
+ 'org.freedesktop.login1.Manager',
+ system_bus=True,
+ stdout=subprocess.PIPE)
+ self.obj_logind = self.system_bus_con.get_object(
+ 'org.freedesktop.login1', '/org/freedesktop/login1')
+
+ self.obj_logind.AddMethods('',
+ [
+ ('PowerOff', 'b', '', ''),
+ ('Suspend', 'b', '', ''),
+ ('Hibernate', 'b', '', ''),
+ ('Inhibit', 'ssss', 'h', 'ret = 5'),
+ ], dbus_interface='org.freedesktop.DBus.Mock')
+
+ # set log to nonblocking
+ set_nonblock(self.logind.stdout)
+
+ def stop_logind(self):
+ '''stop mock logind'''
+
+ self.logind.terminate()
+ self.logind.wait()
+
+ @classmethod
+ def reset_idle_timer(klass):
+ '''trigger activity to reset idle timer'''
+
+ subprocess.check_call([os.path.join(top_builddir, 'tests', 'shiftkey')])
diff --git a/tests/shiftkey.c b/tests/shiftkey.c
new file mode 100644
index 0000000..f02fc93
--- /dev/null
+++ b/tests/shiftkey.c
@@ -0,0 +1,56 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 8 -*-
+ *
+ * Test helper program to send a "left shift key" event via XTest, to reset the
+ * idle timer.
+ *
+ * Copyright (C) 2013 Canonical Ltd.
+ * Author: Martin Pitt <martin pitt ubuntu com>
+ *
+ * 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ */
+
+#include "config.h"
+
+#include <stdio.h>
+
+#include <X11/extensions/XTest.h>
+#include <X11/keysym.h>
+
+int
+main()
+{
+ Display *display = NULL;
+ int event_base, error_base, major_version, minor_version;
+
+ display = XOpenDisplay (NULL);
+
+ if (display == NULL) {
+ fputs ("Error: Cannot open display\n", stderr);
+ return 1;
+ }
+
+ if (!XTestQueryExtension (display, &event_base, &error_base, &major_version, &minor_version)) {
+ fputs ("Error: No XTest extension\n", stderr);
+ return 1;
+ }
+
+ /* send a left shift key; first press, then release */
+ XTestFakeKeyEvent (display, XK_Shift_L, True, 0);
+ XTestFakeKeyEvent (display, XK_Shift_L, False, 0);
+
+ XCloseDisplay (display);
+ return 0;
+}
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]