Commit 66317081 authored by Sam Thursfield's avatar Sam Thursfield

functional-tests: Use GDBus instead of dbus-python

dbus-python is deprecated.
parent 37f4b5e5
......@@ -22,7 +22,7 @@
Stand-alone tests cases for the store, inserting, removing information
in pure sparql and checking that the data is really there
"""
import sys,os,dbus
import sys,os
import unittest
import time
import random
......
......@@ -21,7 +21,7 @@
"""
Peculiar Sparql behavour reported in bugs
"""
import sys,os,dbus
import sys,os
import unittest
import time
import random
......@@ -197,7 +197,7 @@ class TrackerStoreSparqlBugsTests (CommonTrackerStoreTest):
original_data = self.tracker.query (query)
wrong_insert = "INSERT { <test://nb222645-wrong-class-contact> a nco:IMContact. } "
self.assertRaises (dbus.DBusException,
self.assertRaises (GLib.Error,
self.tracker.update,
wrong_insert)
......
......@@ -22,7 +22,6 @@
These tests use only the store. They insert instances with known text
and run sparql with fts functions to check the results.
"""
import dbus
import unittest
import random
......
......@@ -20,7 +20,6 @@
"""
Test the GROUP_CONCAT function in Sparql. Only requires the store.
"""
import dbus
import unittest
import random
......
......@@ -20,7 +20,6 @@
"""
Test tracker:coalesce function in Sparql. Only uses the Store
"""
import dbus
import unittest
import random
......
......@@ -20,7 +20,6 @@
"""
Test the distance-calculation functions in Sparql. Only requires the Store
"""
import dbus
import unittest
import random
......
......@@ -20,7 +20,6 @@
"""
Tests graphs in Sparql. Only requires the store.
"""
import dbus
import unittest
import random
......
......@@ -20,7 +20,6 @@
"""
Replicate the behaviour of the miner inserting information in the store.
"""
import dbus
import unittest
import random
......
......@@ -20,14 +20,13 @@
"""
Send concurrent inserts and queries to the daemon to check the concurrency.
"""
import sys,os,dbus
import sys,os
import unittest
import time
import random
import commands
import signal
from gi.repository import GObject
from dbus.mainloop.glib import DBusGMainLoop
from common.utils import configuration as cfg
import unittest2 as ut
......@@ -73,24 +72,26 @@ class TestConcurrentQuery (CommonTrackerStoreTest):
QUERY = "SELECT ?u WHERE { ?u a nco:PersonContact. FILTER regex (?u, 'test-09:ins')}"
UPDATE = "INSERT { <test-09:picture-%d> a nmm:Photo. }"
for i in range (0, AMOUNT_OF_QUERIES):
self.tracker.get_tracker_iface ().SparqlQuery (QUERY,
reply_handler=self.reply_cb,
error_handler=self.error_handler)
self.tracker.get_tracker_iface ().SparqlUpdate (UPDATE % (i),
reply_handler=self.update_cb,
error_handler=self.error_handler)
self.tracker.query(
QUERY,
result_handler=self.reply_cb,
error_handler=self.error_handler)
self.tracker.update(
UPDATE % (i),
result_handler=self.update_cb,
error_handler=self.error_handler)
# Safeguard of 50 seconds. The last reply should quit the loop
GObject.timeout_add_seconds (60, self.timeout_cb)
self.main_loop.run ()
def reply_cb (self, results):
def reply_cb (self, obj, results, data):
self.finish_counter += 1
self.assertEquals (len (results), AMOUNT_OF_TEST_INSTANCES)
if (self.finish_counter >= AMOUNT_OF_QUERIES):
self.timeout_cb ()
def update_cb (self):
def update_cb (self, obj, results, data):
self.assertTrue (True)
def error_handler (self):
......
......@@ -21,9 +21,8 @@
Test the query while importing at the same time. This was raising
some SQLITE_MISUSED errors before.
"""
import os, dbus
import os
from gi.repository import GObject
from dbus.mainloop.glib import DBusGMainLoop
from common.utils import configuration as cfg
import unittest2 as ut
......@@ -44,11 +43,11 @@ class TestSqliteMisused (CommonTrackerStoreTest):
for ttl_file in filter (lambda f: f.endswith (".ttl"), files):
full_path = os.path.abspath(os.path.join (root, ttl_file))
self.files_counter += 1
self.tracker.get_tracker_iface ().Load ("file://" + full_path,
timeout=30000,
reply_handler=self.loaded_success_cb,
error_handler=self.loaded_failed_cb)
self.tracker.query(
"file://" + full_path, timeout=30000,
result_handler=self.loaded_success_cb,
error_handler=self.loaded_failed_cb)
GObject.timeout_add_seconds (2, self.run_a_query)
# Safeguard of 60 seconds. The last reply should quit the loop
GObject.timeout_add_seconds (60, self.timeout_cb)
......@@ -56,18 +55,19 @@ class TestSqliteMisused (CommonTrackerStoreTest):
def run_a_query (self):
QUERY = "SELECT ?u ?title WHERE { ?u a nie:InformationElement; nie:title ?title. }"
self.tracker.get_tracker_iface ().SparqlQuery (QUERY, timeout=20000,
reply_handler=self.reply_cb,
error_handler=self.error_handler)
self.tracker.query(
QUERY, timeout=20000,
result_handler=self.reply_cb,
error_handler=self.error_handler)
return True
def reply_cb (self, results):
def reply_cb (self, obj, results, data):
print "Query replied correctly"
def error_handler (self, error_msg):
print "ERROR in DBus call", error_msg
def loaded_success_cb (self):
def loaded_success_cb (self, obj, results, data):
self.files_counter -= 1
if (self.files_counter == 0):
print "Last file loaded"
......
......@@ -21,9 +21,8 @@
Test the query while running BatchSparqlUpdate at the same time. This was raising
some SQLITE_MISUSED errors before.
"""
import os, dbus
import os
from gi.repository import GObject
from dbus.mainloop.glib import DBusGMainLoop
from common.utils import configuration as cfg
import unittest2 as ut
......@@ -62,10 +61,11 @@ class TestSqliteBatchMisused (CommonTrackerStoreTest):
if counter == BATCH_SIZE:
query = "INSERT {" + current_batch + "}"
self.tracker.get_tracker_iface ().BatchSparqlUpdate (query,
timeout=20000,
reply_handler=self.batch_success_cb,
error_handler=self.batch_failed_cb)
self.tracker.batch_update(
query,
timeout=20000,
result_handler=self.batch_success_cb,
error_handler=self.batch_failed_cb)
self.run_a_query ()
counter = 0
current_batch = ""
......@@ -79,12 +79,13 @@ class TestSqliteBatchMisused (CommonTrackerStoreTest):
def run_a_query (self):
QUERY = "SELECT ?u ?title WHERE { ?u a nie:InformationElement; nie:title ?title. }"
self.tracker.get_tracker_iface ().SparqlQuery (QUERY, timeout=20000,
reply_handler=self.reply_cb,
error_handler=self.error_handler)
self.tracker.query(
QUERY, timeout=20000,
reply_handler=self.reply_cb,
error_handler=self.error_handler)
return True
def reply_cb (self, results):
def reply_cb (self, obj, results, data):
print "Query replied correctly"
def error_handler (self, error_msg):
......
......@@ -63,8 +63,8 @@ class TestThreadedStore (CommonTrackerStoreTest):
"016-nco_ContactIM.ttl"]:
full_path = os.path.abspath(os.path.join ("ttl", ttl_file))
print full_path
self.tracker.get_tracker_iface ().Load ("file://" + full_path,
timeout=30000)
self.tracker.get_tracker_iface().Load(
'(s)', "file://" + full_path, timeout=30000)
def test_complex_query (self):
start = time.time ()
......@@ -97,9 +97,10 @@ class TestThreadedStore (CommonTrackerStoreTest):
# Standard timeout
print "Send complex query"
self.complex_start = time.time ()
self.tracker.get_tracker_iface ().SparqlQuery (COMPLEX_QUERY, timeout=COMPLEX_QUERY_TIMEOUT,
reply_handler=self.reply_complex,
error_handler=self.error_handler_complex)
self.tracker.query(
COMPLEX_QUERY, timeout=COMPLEX_QUERY_TIMEOUT,
response_handler=self.reply_complex,
error_handler=self.error_handler_complex)
self.timeout_id = GLib.timeout_add_seconds (MAX_TEST_TIME, self.__timeout_on_idle)
GLib.timeout_add_seconds (SIMPLE_QUERY_FREQ, self.__simple_query)
......@@ -108,17 +109,18 @@ class TestThreadedStore (CommonTrackerStoreTest):
def __simple_query (self):
print "Send simple query (%d)" % (self.simple_queries_counter)
SIMPLE_QUERY = "SELECT ?name WHERE { ?u a nco:PersonContact; nco:fullname ?name. }"
self.tracker.get_tracker_iface ().SparqlQuery (SIMPLE_QUERY,
timeout=10000,
reply_handler=self.reply_simple,
error_handler=self.error_handler)
self.tracker.query(
SIMPLE_QUERY,
timeout=10000,
response_handler=self.reply_simple,
error_handler=self.error_handler)
self.simple_queries_counter -= 1
if (self.simple_queries_counter == 0):
print "Stop sending queries (wait)"
return False
return True
def reply_simple (self, results):
def reply_simple (self, obj, results, data):
print "Simple query answered"
self.assertNotEquals (len (results), 0)
self.simple_queries_answers += 1
......@@ -126,7 +128,7 @@ class TestThreadedStore (CommonTrackerStoreTest):
print "All simple queries answered"
self.main_loop.quit ()
def reply_complex (self, results):
def reply_complex (self, obj, results, data):
print "Complex query: %.3f" % (time.time () - self.complex_start)
def error_handler (self, error_msg):
......
......@@ -27,10 +27,9 @@ import unittest2 as ut
from common.utils.storetest import CommonTrackerStoreTest as CommonTrackerStoreTest
from common.utils import configuration as cfg
from gi.repository import Gio
from gi.repository import GObject
from gi.repository import GLib
import dbus
from dbus.mainloop.glib import DBusGMainLoop
import time
GRAPH_UPDATED_SIGNAL = "GraphUpdated"
......@@ -49,11 +48,12 @@ class TrackerStoreSignalsTests (CommonTrackerStoreTest):
"""
def setUp (self):
self.clean_up_list = []
self.loop = GObject.MainLoop()
dbus_loop = DBusGMainLoop(set_as_default=True)
self.bus = dbus.SessionBus (dbus_loop)
self.timeout_id = 0
self.bus = Gio.bus_get_sync(Gio.BusType.SESSION, None)
self.results_classname = None
self.results_deletes = None
self.results_inserts = None
......@@ -69,11 +69,14 @@ class TrackerStoreSignalsTests (CommonTrackerStoreTest):
"""
After connecting to the signal, call self.__wait_for_signal.
"""
self.cb_id = self.bus.add_signal_receiver (self.__signal_received_cb,
signal_name=GRAPH_UPDATED_SIGNAL,
path = SIGNALS_PATH,
dbus_interface = SIGNALS_IFACE,
arg0 = CONTACT_CLASS_URI)
self.cb_id = self.bus.signal_subscribe(
sender=cfg.TRACKER_BUSNAME,
interface_name=SIGNALS_IFACE,
member=GRAPH_UPDATED_SIGNAL,
object_path=SIGNALS_PATH,
arg0=CONTACT_CLASS_URI,
flags=Gio.DBusSignalFlags.NONE,
callback=self.__signal_received_cb)
def __wait_for_signal (self):
"""
......@@ -91,10 +94,12 @@ class TrackerStoreSignalsTests (CommonTrackerStoreTest):
uri, prop, value = self.tracker.query ("SELECT tracker:uri (%s), tracker:uri (%s), tracker:uri (%s) WHERE {}" % (s, o, p))
print " - (", "-".join ([g, uri, prop, value]), ")"
def __signal_received_cb (self, classname, deletes, inserts):
def __signal_received_cb (self, connection, sender_name, object_path, interface_name, signal_name, parameters):
"""
Save the content of the signal and disconnect the callback
"""
classname, deletes, inserts = parameters.unpack()
self.results_classname = classname
self.results_deletes = deletes
self.results_inserts = inserts
......@@ -103,7 +108,7 @@ class TrackerStoreSignalsTests (CommonTrackerStoreTest):
GLib.source_remove (self.timeout_id )
self.timeout_id = 0
self.loop.quit ()
self.bus._clean_up_signal_match (self.cb_id)
self.bus.signal_unsubscribe(self.cb_id)
def test_01_insert_contact (self):
......
......@@ -22,10 +22,12 @@
Stand-alone tests cases for the store, booting it with different ontology
changes and checking if the data is still there.
"""
from gi.repository import GLib
import time
import os
import dbus # Just for the Exception
from common.utils import configuration as cfg
import unittest2 as ut
#import unittest as ut
......@@ -791,7 +793,7 @@ class PropertyPromotionTest (OntologyChangeTestTemplate):
""" % (self.instance_b))
self.instance_a = "test://ontology-change/property/promotion-to-superclass/a"
self.assertRaises (dbus.DBusException,
self.assertRaises (GLib.Error,
self.tracker.update,
"INSERT { <%s> a test:A; test:b_property 'content-a-test'.}" % (self.instance_a))
......@@ -832,7 +834,7 @@ class PropertyRelegationTest (OntologyChangeTestTemplate):
def validate_status (self):
# This insertion should fail now
self.assertRaises (dbus.DBusException,
self.assertRaises (GLib.Error,
self.tracker.update,
"INSERT { <%s> a test:A; test:b_property 'content-a-test'.}" % (self.instance_a))
# No data loss
......
......@@ -17,8 +17,9 @@
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
# 02110-1301, USA.
#
from gi.repository import GLib
import os
import dbus # For the exception handling
from common.utils.system import TrackerSystemAbstraction
from common.utils.helpers import StoreHelper
......@@ -120,9 +121,9 @@ class BackupRestoreTest (CommonTrackerStoreTest):
trashfile.write ("Here some useless text that obviously is NOT a backup")
trashfile.close ()
self.assertRaises (dbus.DBusException,
self.tracker.restore,
"file://" + TEST_FILE)
self.assertRaises(GLib.Error,
self.tracker.restore,
"file://" + TEST_FILE)
os.unlink (TEST_FILE)
def test_backup_04 (self):
......@@ -139,9 +140,9 @@ class BackupRestoreTest (CommonTrackerStoreTest):
trashfile.close ()
instances_before = self.tracker.count_instances ("nie:InformationElement")
self.assertRaises (dbus.DBusException,
self.tracker.restore,
"file://" + TEST_FILE)
self.assertRaises(GLib.Error,
self.tracker.restore,
"file://" + TEST_FILE)
os.unlink (TEST_FILE)
......@@ -150,18 +151,18 @@ class BackupRestoreTest (CommonTrackerStoreTest):
Take backup of db to a invalid path.
Expected: Backup should not be taken and tracker should behave normally.
"""
self.assertRaises (dbus.DBusException,
self.tracker.backup,
"file://%s/this/is/a/non-existant/folder/backup" % (cfg.TEST_TMP_DIR))
self.assertRaises(GLib.Error,
self.tracker.backup,
"file://%s/this/is/a/non-existant/folder/backup" % (cfg.TEST_TMP_DIR))
def test_backup_06 (self):
"""
Try to restore an invalid path
"""
self.assertRaises (dbus.DBusException,
self.tracker.restore,
"file://%s/this/is/a/non-existant/folder/backup" % (cfg.TEST_TMP_DIR))
self.assertRaises(GLib.Error,
self.tracker.restore,
"file://%s/this/is/a/non-existant/folder/backup" % (cfg.TEST_TMP_DIR))
def test_backup_07(self):
......
......@@ -21,7 +21,7 @@
Write values in tracker and check the actual values are written
on the files. Note that these tests are highly platform dependant.
"""
import os, dbus
import os
import time
from common.utils.extractor import get_tracker_extract_output
......
......@@ -17,14 +17,13 @@
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
# 02110-1301, USA.
#
import dbus
from gi.repository import Gio
from gi.repository import GLib
from gi.repository import GObject
import os
import sys
import subprocess
import time
from dbus.mainloop.glib import DBusGMainLoop
import re
import configuration as cfg
......@@ -59,11 +58,18 @@ class Helper:
PROCESS_NAME = None
def __init__ (self):
self.loop = None
self.bus = None
self.bus_admin = None
self.process = None
self.available = False
self.loop = GObject.MainLoop ()
self.install_glib_excepthook(self.loop)
self.bus = Gio.bus_get_sync(Gio.BusType.SESSION, None)
Gio.bus_watch_name_on_connection(
self.bus, self.BUS_NAME, Gio.BusNameWatcherFlags.NONE,
self._bus_name_appeared, self._bus_name_vanished)
self.loop.run()
def install_glib_excepthook(self, loop):
"""
......@@ -76,21 +82,6 @@ class Helper:
sys.exit()
sys.excepthook = new_hook
def _get_bus (self):
if self.bus is not None:
return
self.loop = GObject.MainLoop ()
self.install_glib_excepthook(self.loop)
dbus_loop = DBusGMainLoop (set_as_default=True)
self.bus = dbus.SessionBus (dbus_loop)
obj = self.bus.get_object ("org.freedesktop.DBus",
"/org/freedesktop/DBus")
self.bus_admin = dbus.Interface (obj, dbus_interface = "org.freedesktop.DBus")
def _start_process (self):
path = getattr (self,
"PROCESS_PATH",
......@@ -109,18 +100,15 @@ class Helper:
log ("Starting %s" % ' '.join(command))
return subprocess.Popen ([path] + flags, **kws)
def _name_owner_changed_cb (self, name, old_owner, new_owner):
if name == self.BUS_NAME:
if old_owner == '' and new_owner != '':
log ("[%s] appeared in the bus" % self.PROCESS_NAME)
self.available = True
elif old_owner != '' and new_owner == '':
log ("[%s] disappeared from the bus" % self.PROCESS_NAME)
self.available = False
else:
log ("[%s] name change %s -> %s" % (self.PROCESS_NAME, old_owner, new_owner))
def _bus_name_appeared(self, name, owner, data):
log ("[%s] appeared in the bus as %s" % (self.PROCESS_NAME, owner))
self.available = True
self.loop.quit()
self.loop.quit ()
def _bus_name_vanished(self, name, data):
log ("[%s] disappeared from the bus" % self.PROCESS_NAME)
self.available = False
self.loop.quit()
def _process_watch_cb (self):
status = self.process.poll ()
......@@ -139,34 +127,19 @@ class Helper:
self.timeout_id = None
return False
def start (self):
"""
Start an instance of process and wait for it to appear on the bus.
"""
self._get_bus ()
if self.bus_admin.NameHasOwner(self.BUS_NAME):
if options.is_manual_start():
self.available = True
log ("Found existing %s process (D-Bus name %s)" %
(self.PROCESS_NAME, self.BUS_NAME))
return
else:
raise Exception ("Unable to start test instance of %s: "
"already running" % self.PROCESS_NAME)
else:
log ("Name %s does not have an owner." % self.BUS_NAME)
self.name_owner_match = self.bus.add_signal_receiver (self._name_owner_changed_cb,
signal_name="NameOwnerChanged",
path="/org/freedesktop/DBus",
dbus_interface="org.freedesktop.DBus")
if options.is_manual_start():
print ("Start %s manually" % self.PROCESS_NAME)
else:
if self.available:
# It's running, but we didn't start it...
raise Exception ("Unable to start test instance of %s: "
"already running " % self.PROCESS_NAME)
self.process = self._start_process ()
log ('[%s] Started process %i' % (self.PROCESS_NAME, self.process.pid))
self.process_watch_timeout = GLib.timeout_add (200, self._process_watch_cb)
......@@ -199,8 +172,9 @@ class Helper:
self.process.wait()
log ("[%s] stopped." % self.PROCESS_NAME)
# Disconnect the signals of the next start we get duplicated messages
self.bus._clean_up_signal_match (self.name_owner_match)
# Run the loop until the bus name appears, or the process dies.
self.loop.run ()
def kill (self):
self.process.kill ()
......@@ -209,7 +183,6 @@ class Helper:
self.loop.run ()
log ("[%s] killed." % self.PROCESS_NAME)
self.bus._clean_up_signal_match (self.name_owner_match)
class StoreHelper (Helper):
......@@ -228,37 +201,40 @@ class StoreHelper (Helper):
def start (self):
Helper.start (self)
tracker = self.bus.get_object (cfg.TRACKER_BUSNAME,
cfg.TRACKER_OBJ_PATH)
self.resources = dbus.Interface (tracker,
dbus_interface=cfg.RESOURCES_IFACE)
tracker_backup = self.bus.get_object (cfg.TRACKER_BUSNAME, cfg.TRACKER_BACKUP_OBJ_PATH)
self.backup_iface = dbus.Interface (tracker_backup, dbus_interface=cfg.BACKUP_IFACE)
self.resources = Gio.DBusProxy.new_sync(
self.bus, Gio.DBusProxyFlags.DO_NOT_AUTO_START, None,
cfg.TRACKER_BUSNAME, cfg.TRACKER_OBJ_PATH, cfg.RESOURCES_IFACE)
tracker_stats = self.bus.get_object (cfg.TRACKER_BUSNAME, cfg.TRACKER_STATS_OBJ_PATH)
self.backup_iface = Gio.DBusProxy.new_sync(
self.bus, Gio.DBusProxyFlags.DO_NOT_AUTO_START, None,
cfg.TRACKER_BUSNAME, cfg.TRACKER_BACKUP_OBJ_PATH, cfg.BACKUP_IFACE)
self.stats_iface = dbus.Interface (tracker_stats, dbus_interface=cfg.STATS_IFACE)
self.stats_iface = Gio.DBusProxy.new_sync(
self.bus, Gio.DBusProxyFlags.DO_NOT_AUTO_START, None,
cfg.TRACKER_BUSNAME, cfg.TRACKER_STATS_OBJ_PATH, cfg.STATS_IFACE)
tracker_status = self.bus.get_object (cfg.TRACKER_BUSNAME,
cfg.TRACKER_STATUS_OBJ_PATH)
self.status_iface = dbus.Interface (tracker_status, dbus_interface=cfg.STATUS_IFACE)
self.status_iface = Gio.DBusProxy.new_sync(
self.bus, Gio.DBusProxyFlags.DO_NOT_AUTO_START, None,
cfg.TRACKER_BUSNAME, cfg.TRACKER_STATUS_OBJ_PATH, cfg.STATUS_IFACE)
log ("[%s] booting..." % self.PROCESS_NAME)
self.status_iface.Wait ()
log ("[%s] ready." % self.PROCESS_NAME)
self.reset_graph_updates_tracking ()
self.graph_updated_handler_id = self.bus.add_signal_receiver (self._graph_updated_cb,
signal_name = "GraphUpdated",
path = cfg.TRACKER_OBJ_PATH,
dbus_interface = cfg.RESOURCES_IFACE)
def signal_handler(proxy, sender_name, signal_name, parameters):
if signal_name == 'GraphUpdated':
self._graph_updated_cb(*parameters.unpack())
self.graph_updated_handler_id = self.resources.connect(
'g-signal', signal_handler)
def stop (self):
Helper.stop (self)
self.bus._clean_up_signal_match (self.graph_updated_handler_id)
if self.graph_updated_handler_id != 0:
self.resources.disconnect(self.graph_updated_handler_id)
# A system to follow GraphUpdated and make sure all changes are tracked.
# This code saves every change notification received, and exposes methods
......@@ -472,63 +448,26 @@ class StoreHelper (Helper):
raise Exception ("Timeout waiting for property change, subject %i "
"property %s" % (subject_id, property_uri))
def query (self, query, timeout=5000):
try:
return self.resources.SparqlQuery (query, timeout=timeout)
except dbus.DBusException as (e):
if (e.get_dbus_name().startswith ("org.freedesktop.DBus")):
self.start ()
return self.resources.SparqlQuery (query, timeout=timeout)
raise (e)
def update (self, update_sparql, timeout=5000):
try:
return self.resources.SparqlUpdate (update_sparql, timeout=timeout)
except dbus.DBusException as (e):
if (e.get_dbus_name().startswith ("org.freedesktop.DBus")):
self.start ()
return self.resources.SparqlUpdate (update_sparql, timeout=timeout)
raise (e)
def batch_update (self, update_sparql):
try:
return self.resources.BatchSparqlUpdate (update_sparql)
except dbus.DBusException as (e):
if (e.get_dbus_name().startswith ("org.freedesktop.DBus")):
self.start ()
return self.resources.BatchSparqlUpdate (update_sparql)
raise (e)
def batch_commit (self):
return self.resources.BatchCommit ()
def backup (self, backup_file):
try:
self.backup_iface.Save (backup_file)
except dbus.DBusException as (e):
if (e.get_dbus_name().startswith ("org.freedesktop.DBus")):
self.start ()
return self.backup_iface.Save (backup_file)
raise (e)