From 8249e264e0f426d6702d21a690477be495045f90 Mon Sep 17 00:00:00 2001 From: Lars Uebernickel Date: Tue, 19 Feb 2013 19:21:43 -0500 Subject: Notify the service when an app unrefs its MessagingMenuApp Prior to this patch, the messaging menu only marked apps as "not running" when they quit (i.e. disappeared from the bus). This was okay, since most applications only ever release the ref to their MessagingMenuApp when they quit, or after calling _unregister explicitely (which removes them from the menu entirely). However, this is according to libmessagingmenu's documentation, and at least indicator-telepathy relies on it. --- libmessaging-menu/messaging-menu.c | 4 ++++ src/messages-service.c | 25 +++++++++++++++++++++++++ src/messages-service.xml | 4 ++++ 3 files changed, 33 insertions(+) diff --git a/libmessaging-menu/messaging-menu.c b/libmessaging-menu/messaging-menu.c index 04f8d1d..a51695a 100644 --- a/libmessaging-menu/messaging-menu.c +++ b/libmessaging-menu/messaging-menu.c @@ -277,6 +277,10 @@ messaging_menu_app_dispose (GObject *object) if (app->messages_service) { + indicator_messages_service_call_application_stopped_running (app->messages_service, + g_app_info_get_id (G_APP_INFO (app->appinfo)), + NULL, NULL, NULL); + g_signal_handlers_disconnect_by_func (app->messages_service, global_status_changed, app); diff --git a/src/messages-service.c b/src/messages-service.c index 48c830e..e48e3f8 100644 --- a/src/messages-service.c +++ b/src/messages-service.c @@ -472,6 +472,29 @@ unregister_application (IndicatorMessagesService *service, indicator_messages_service_complete_unregister_application (service, invocation); } +static void +application_stopped_running (IndicatorMessagesService *service, + GDBusMethodInvocation *invocation, + const gchar *desktop_id, + gpointer user_data) +{ + GDesktopAppInfo *appinfo; + gchar *id; + AppSection *section; + + indicator_messages_service_complete_application_stopped_running (service, invocation); + + if (!(appinfo = g_desktop_app_info_new (desktop_id))) + return; + + id = g_app_info_get_simple_id (G_APP_INFO (appinfo)); + section = g_hash_table_lookup (applications, id); + app_section_unset_object_path (section); + + g_free (id); + g_object_unref (appinfo); +} + static void set_status (IndicatorMessagesService *service, GDBusMethodInvocation *invocation, @@ -648,6 +671,8 @@ main (int argc, char ** argv) G_CALLBACK (register_application), NULL); g_signal_connect (messages_service, "handle-unregister-application", G_CALLBACK (unregister_application), NULL); + g_signal_connect (messages_service, "handle-application-stopped-running", + G_CALLBACK (application_stopped_running), NULL); g_signal_connect (messages_service, "handle-set-status", G_CALLBACK (set_status), NULL); diff --git a/src/messages-service.xml b/src/messages-service.xml index 00ae154..3c3c779 100644 --- a/src/messages-service.xml +++ b/src/messages-service.xml @@ -11,6 +11,10 @@ + + + + -- cgit v1.2.3 From 5c47f6dbe75e413d2acbcef3e9750e937fb18431 Mon Sep 17 00:00:00 2001 From: Lars Uebernickel Date: Mon, 25 Feb 2013 19:34:56 -0500 Subject: Test libmessaging-menu Use dbusmock to test whether libmessaging-menu calls the right functions on registration and deregistration. --- configure.ac | 18 +++++++++----- debian/control | 1 + test/Makefile.am | 10 ++++++++ test/test-client.py | 68 +++++++++++++++++++++++++++++++++++++++++++++++++++++ 4 files changed, 91 insertions(+), 6 deletions(-) create mode 100755 test/test-client.py diff --git a/configure.ac b/configure.ac index bcd7b20..08ac680 100644 --- a/configure.ac +++ b/configure.ac @@ -75,7 +75,7 @@ AC_SUBST(COVERAGE_CXXFLAGS) AC_SUBST(COVERAGE_LDFLAGS) ########################### -# Google Test framework +# Tests ########################### AC_ARG_ENABLE([tests], @@ -85,10 +85,16 @@ AC_ARG_ENABLE([tests], if test "x$enable_tests" != "xno"; then m4_include([m4/gtest.m4]) CHECK_GTEST - if test "x$enable_tests" = "xauto"; then - enable_tests=${have_gtest} - elif test "x$enable_tests" = "xyes" && test "x$have_gtest" != "xyes"; then - AC_MSG_ERROR([tests were requested but gtest is not installed.]) + AM_PATH_PYTHON(3.0,, [:]) + AC_PYTHON_MODULE(dbusmock) + if test "x$have_gtest" = "xyes" -a "x$HAVE_PYMOD_DBUSMOCK" = "xyes"; then + enable_tests="yes" + else + if test "x$enable_tests" = "xyes"; then + AC_MSG_ERROR([tests were requested but gtest or dbusmock are not installed.]) + else + enable_tests="no" + fi fi fi AM_CONDITIONAL([BUILD_TESTS],[test "x$enable_tests" = "xyes"]) @@ -193,7 +199,7 @@ Messaging Indicator Configuration: Prefix: $prefix Indicator Dir: $INDICATORDIR - gtest: $enable_tests + tests: $enable_tests gcov: $use_gcov introspecion: $enable_introspection documentation: $enable_gtk_doc diff --git a/debian/control b/debian/control index 31292c5..efc21cd 100644 --- a/debian/control +++ b/debian/control @@ -19,6 +19,7 @@ Build-Depends: debhelper (>= 9), libgirepository1.0-dev (>= 0.9.12), gtk-doc-tools, libgtest-dev, + python3-dbusmock, Standards-Version: 3.9.3 Homepage: https://launchpad.net/indicator-messages # If you aren't a member of ~indicator-applet-developers but need to upload diff --git a/test/Makefile.am b/test/Makefile.am index 4671446..87ae2c3 100644 --- a/test/Makefile.am +++ b/test/Makefile.am @@ -65,3 +65,13 @@ libindicator_messages_service_la_LIBADD = \ libindicator_messages_service_la_LDFLAGS = \ $(COVERAGE_LDFLAGS) + +###################################### +# Test client with dbusmock +###################################### + +TESTS_ENVIRONMENT = \ + export LD_LIBRARY_PATH=$(top_builddir)/libmessaging-menu/.libs; \ + export GI_TYPELIB_PATH=$(top_builddir)/libmessaging-menu; + +TESTS += test-client.py diff --git a/test/test-client.py b/test/test-client.py new file mode 100755 index 0000000..e012d6e --- /dev/null +++ b/test/test-client.py @@ -0,0 +1,68 @@ +#!/usr/bin/env python3 + +import unittest +import dbus +import dbusmock +import subprocess +from gi.repository import GLib, Gio, MessagingMenu + +class MessagingMenuTest(dbusmock.DBusTestCase): + @classmethod + def setUpClass(klass): + klass.start_session_bus() + klass.bus = klass.get_dbus(False) + + def setUp(self): + name = 'com.canonical.indicator.messages' + obj_path = '/com/canonical/indicator/messages/service' + iface = 'com.canonical.indicator.messages.service' + + self.messaging_service = self.spawn_server(name, obj_path, iface, stdout=subprocess.PIPE) + self.mock = dbus.Interface(self.bus.get_object(name, obj_path), dbusmock.MOCK_IFACE) + self.mock.AddMethod('', 'RegisterApplication', 'so', '', '') + self.mock.AddMethod('', 'UnregisterApplication', 's', '', '') + self.mock.AddMethod('', 'ApplicationStoppedRunning', 's', '', '') + self.mock.AddMethod('', 'SetStatus', 'ss', '', '') + + self.loop = GLib.MainLoop() + + def tearDown(self): + self.messaging_service.terminate() + self.messaging_service.wait() + + def spin_loop(self, ms=10): + GLib.timeout_add(ms, lambda: self.loop.quit()) + self.loop.run() + + def assertMethodCalled(self, name, *expected_args): + calls = self.mock.GetMethodCalls(name) + self.assertEqual(len(calls), 1, 'method %s was not called' % name) + args = calls[0][1] + self.assertEqual(len(args), len(expected_args)) + for i in range(len(args)): + if expected_args[i]: + self.assertEqual(args[i], expected_args[i]) + + def test_registration(self): + mmapp = MessagingMenu.App.new('empathy.desktop') + mmapp.register() + self.spin_loop() + self.assertMethodCalled('RegisterApplication', 'empathy.desktop', None) + + mmapp.unregister() + self.spin_loop() + self.assertMethodCalled('UnregisterApplication', 'empathy.desktop') + + # ApplicationStoppedRunning is called when the last ref on mmapp is dropped + del mmapp + self.spin_loop() + self.assertMethodCalled('ApplicationStoppedRunning', 'empathy.desktop') + + def test_status(self): + mmapp = MessagingMenu.App.new('empathy.desktop') + mmapp.register() + mmapp.set_status(MessagingMenu.Status.AWAY) + self.spin_loop() + self.assertMethodCalled('SetStatus', 'empathy.desktop', 'away') + +unittest.main(testRunner=unittest.TextTestRunner()) -- cgit v1.2.3 From d98feb7174b8b66059bce11abe5d2c0fb5c418cb Mon Sep 17 00:00:00 2001 From: Lars Uebernickel Date: Tue, 26 Feb 2013 15:17:56 -0500 Subject: debian/control: add autoconf-archive as an explicit build dep Needed for AC_PYTHON_MODULE --- debian/control | 1 + 1 file changed, 1 insertion(+) diff --git a/debian/control b/debian/control index efc21cd..c0a8290 100644 --- a/debian/control +++ b/debian/control @@ -20,6 +20,7 @@ Build-Depends: debhelper (>= 9), gtk-doc-tools, libgtest-dev, python3-dbusmock, + autoconf-archive, Standards-Version: 3.9.3 Homepage: https://launchpad.net/indicator-messages # If you aren't a member of ~indicator-applet-developers but need to upload -- cgit v1.2.3 From 83b5fdc85d50f68722bd1b2cad69e4519ab9b25f Mon Sep 17 00:00:00 2001 From: Lars Uebernickel Date: Tue, 26 Feb 2013 19:34:14 -0500 Subject: Use a special desktop file for testing --- test/Makefile.am | 3 ++- test/applications/test.desktop | 2 ++ test/test-client.py | 12 ++++++------ 3 files changed, 10 insertions(+), 7 deletions(-) create mode 100644 test/applications/test.desktop diff --git a/test/Makefile.am b/test/Makefile.am index 87ae2c3..4f1a163 100644 --- a/test/Makefile.am +++ b/test/Makefile.am @@ -72,6 +72,7 @@ libindicator_messages_service_la_LDFLAGS = \ TESTS_ENVIRONMENT = \ export LD_LIBRARY_PATH=$(top_builddir)/libmessaging-menu/.libs; \ - export GI_TYPELIB_PATH=$(top_builddir)/libmessaging-menu; + export GI_TYPELIB_PATH=$(top_builddir)/libmessaging-menu; \ + export XDG_DATA_DIRS=$(abs_srcdir); TESTS += test-client.py diff --git a/test/applications/test.desktop b/test/applications/test.desktop new file mode 100644 index 0000000..c2332b9 --- /dev/null +++ b/test/applications/test.desktop @@ -0,0 +1,2 @@ +[Desktop Entry] +Type=Application diff --git a/test/test-client.py b/test/test-client.py index e012d6e..af5d119 100755 --- a/test/test-client.py +++ b/test/test-client.py @@ -44,25 +44,25 @@ class MessagingMenuTest(dbusmock.DBusTestCase): self.assertEqual(args[i], expected_args[i]) def test_registration(self): - mmapp = MessagingMenu.App.new('empathy.desktop') + mmapp = MessagingMenu.App.new('test.desktop') mmapp.register() self.spin_loop() - self.assertMethodCalled('RegisterApplication', 'empathy.desktop', None) + self.assertMethodCalled('RegisterApplication', 'test.desktop', None) mmapp.unregister() self.spin_loop() - self.assertMethodCalled('UnregisterApplication', 'empathy.desktop') + self.assertMethodCalled('UnregisterApplication', 'test.desktop') # ApplicationStoppedRunning is called when the last ref on mmapp is dropped del mmapp self.spin_loop() - self.assertMethodCalled('ApplicationStoppedRunning', 'empathy.desktop') + self.assertMethodCalled('ApplicationStoppedRunning', 'test.desktop') def test_status(self): - mmapp = MessagingMenu.App.new('empathy.desktop') + mmapp = MessagingMenu.App.new('test.desktop') mmapp.register() mmapp.set_status(MessagingMenu.Status.AWAY) self.spin_loop() - self.assertMethodCalled('SetStatus', 'empathy.desktop', 'away') + self.assertMethodCalled('SetStatus', 'test.desktop', 'away') unittest.main(testRunner=unittest.TextTestRunner()) -- cgit v1.2.3 From 701aadff88796f71250442156f6e3385648d7b05 Mon Sep 17 00:00:00 2001 From: Lars Uebernickel Date: Wed, 27 Feb 2013 12:56:24 -0500 Subject: test-client: wait a bit longer until checking that mock methods were called --- test/test-client.py | 28 ++++++++++++++++------------ 1 file changed, 16 insertions(+), 12 deletions(-) diff --git a/test/test-client.py b/test/test-client.py index af5d119..a4ac8d2 100755 --- a/test/test-client.py +++ b/test/test-client.py @@ -30,39 +30,43 @@ class MessagingMenuTest(dbusmock.DBusTestCase): self.messaging_service.terminate() self.messaging_service.wait() - def spin_loop(self, ms=10): - GLib.timeout_add(ms, lambda: self.loop.quit()) - self.loop.run() - - def assertMethodCalled(self, name, *expected_args): - calls = self.mock.GetMethodCalls(name) - self.assertEqual(len(calls), 1, 'method %s was not called' % name) - args = calls[0][1] + def assertArgumentsEqual(self, args, *expected_args): self.assertEqual(len(args), len(expected_args)) for i in range(len(args)): if expected_args[i]: self.assertEqual(args[i], expected_args[i]) + def assertMethodCalled(self, name, *expected_args): + # set a flag on timeout, assertions don't get bubbled up through c functions + self.timed_out = False + def timeout(): self.timed_out = True + timeout_id = GLib.timeout_add_seconds(10, timeout) + while 1: + calls = self.mock.GetMethodCalls(name) + if len(calls) > 0: + GLib.source_remove(timeout_id) + self.assertArgumentsEqual(calls[0][1], *expected_args) + break + GLib.MainContext.default().iteration(True) + if self.timed_out: + raise self.failureException('method %s was not called after 10 seconds' % name) + def test_registration(self): mmapp = MessagingMenu.App.new('test.desktop') mmapp.register() - self.spin_loop() self.assertMethodCalled('RegisterApplication', 'test.desktop', None) mmapp.unregister() - self.spin_loop() self.assertMethodCalled('UnregisterApplication', 'test.desktop') # ApplicationStoppedRunning is called when the last ref on mmapp is dropped del mmapp - self.spin_loop() self.assertMethodCalled('ApplicationStoppedRunning', 'test.desktop') def test_status(self): mmapp = MessagingMenu.App.new('test.desktop') mmapp.register() mmapp.set_status(MessagingMenu.Status.AWAY) - self.spin_loop() self.assertMethodCalled('SetStatus', 'test.desktop', 'away') unittest.main(testRunner=unittest.TextTestRunner()) -- cgit v1.2.3 From 36a89063932aea9ae94bf67d9c51d80c01bebaa8 Mon Sep 17 00:00:00 2001 From: Lars Uebernickel Date: Tue, 5 Mar 2013 17:54:26 -0500 Subject: Use glib mainloop in dbusmock test --- test/test-client.py | 3 +++ 1 file changed, 3 insertions(+) diff --git a/test/test-client.py b/test/test-client.py index a4ac8d2..a1d503f 100755 --- a/test/test-client.py +++ b/test/test-client.py @@ -2,10 +2,13 @@ import unittest import dbus +from dbus.mainloop.glib import DBusGMainLoop import dbusmock import subprocess from gi.repository import GLib, Gio, MessagingMenu +DBusGMainLoop(set_as_default=True) + class MessagingMenuTest(dbusmock.DBusTestCase): @classmethod def setUpClass(klass): -- cgit v1.2.3 From 014158fd7f63b25840bbcecc92e9ec3f42a7002c Mon Sep 17 00:00:00 2001 From: Lars Uebernickel Date: Fri, 7 Jun 2013 17:35:39 -0400 Subject: Remove autoconf-archive dependency (copied ax_python_module into m4/) --- debian/control | 1 - m4/ax_python_module.m4 | 49 +++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 49 insertions(+), 1 deletion(-) create mode 100644 m4/ax_python_module.m4 diff --git a/debian/control b/debian/control index c0a8290..efc21cd 100644 --- a/debian/control +++ b/debian/control @@ -20,7 +20,6 @@ Build-Depends: debhelper (>= 9), gtk-doc-tools, libgtest-dev, python3-dbusmock, - autoconf-archive, Standards-Version: 3.9.3 Homepage: https://launchpad.net/indicator-messages # If you aren't a member of ~indicator-applet-developers but need to upload diff --git a/m4/ax_python_module.m4 b/m4/ax_python_module.m4 new file mode 100644 index 0000000..bd70a06 --- /dev/null +++ b/m4/ax_python_module.m4 @@ -0,0 +1,49 @@ +# =========================================================================== +# http://www.gnu.org/software/autoconf-archive/ax_python_module.html +# =========================================================================== +# +# SYNOPSIS +# +# AX_PYTHON_MODULE(modname[, fatal]) +# +# DESCRIPTION +# +# Checks for Python module. +# +# If fatal is non-empty then absence of a module will trigger an error. +# +# LICENSE +# +# Copyright (c) 2008 Andrew Collier +# +# Copying and distribution of this file, with or without modification, are +# permitted in any medium without royalty provided the copyright notice +# and this notice are preserved. This file is offered as-is, without any +# warranty. + +#serial 5 + +AU_ALIAS([AC_PYTHON_MODULE], [AX_PYTHON_MODULE]) +AC_DEFUN([AX_PYTHON_MODULE],[ + if test -z $PYTHON; + then + PYTHON="python" + fi + PYTHON_NAME=`basename $PYTHON` + AC_MSG_CHECKING($PYTHON_NAME module: $1) + $PYTHON -c "import $1" 2>/dev/null + if test $? -eq 0; + then + AC_MSG_RESULT(yes) + eval AS_TR_CPP(HAVE_PYMOD_$1)=yes + else + AC_MSG_RESULT(no) + eval AS_TR_CPP(HAVE_PYMOD_$1)=no + # + if test -n "$2" + then + AC_MSG_ERROR(failed to find required module $1) + exit 1 + fi + fi +]) -- cgit v1.2.3