[Telepathy-commits] [telepathy-mission-control/master] Add a basic test infrastructure for Mission Control with python twisted. Details in test/twisted/README.

Alban Crequy alban.crequy at collabora.co.uk
Thu Nov 20 07:43:10 PST 2008


---
 configure.ac                                 |   21 ++
 test/Makefile.am                             |    2 +
 test/twisted/Makefile.am                     |   37 +++
 test/twisted/README                          |   26 ++
 test/twisted/mctest.py                       |   88 +++++
 test/twisted/servicetest.py                  |  450 ++++++++++++++++++++++++++
 test/twisted/test-basic.py                   |   39 +++
 test/twisted/tools/Makefile.am               |   32 ++
 test/twisted/tools/MissionControl.service.in |    3 +
 test/twisted/tools/exec-with-log.sh.in       |   15 +
 test/twisted/tools/tmp-session-bus.conf.in   |   30 ++
 test/twisted/tools/with-session-bus.sh       |   84 +++++
 12 files changed, 827 insertions(+), 0 deletions(-)
 create mode 100644 test/twisted/Makefile.am
 create mode 100644 test/twisted/README
 create mode 100644 test/twisted/mctest.py
 create mode 100644 test/twisted/servicetest.py
 create mode 100644 test/twisted/test-basic.py
 create mode 100644 test/twisted/tools/Makefile.am
 create mode 100644 test/twisted/tools/MissionControl.service.in
 create mode 100644 test/twisted/tools/exec-with-log.sh.in
 create mode 100644 test/twisted/tools/tmp-session-bus.conf.in
 create mode 100644 test/twisted/tools/with-session-bus.sh

diff --git a/configure.ac b/configure.ac
index 59ec6bd..e760c79 100644
--- a/configure.ac
+++ b/configure.ac
@@ -61,6 +61,25 @@ if test -z "$PYTHON"; then
     AC_MSG_ERROR([Python is required to compile this package])
 fi
 
+# Check for a python >= 2.4 with twisted to run python tests
+AC_MSG_CHECKING([for Python >= 2.4 with Twisted and XMPP protocol support])
+for TEST_PYTHON in python2.4 python2.5 python; do
+  if $TEST_PYTHON -c "from sys import version_info;
+      raise SystemExit(version_info < (2, 4, 0, 'final', 0))" \
+      >/dev/null 2>&1; then
+    if $TEST_PYTHON -c "import twisted.words.xish.domish,
+        twisted.words.protocols.jabber, twisted.internet.reactor" \
+        >/dev/null 2>&1; then
+      AC_MSG_RESULT([$TEST_PYTHON])
+      AM_CONDITIONAL([WANT_TWISTED_TESTS], true)
+      break
+    else
+      TEST_PYTHON=false
+    fi
+  fi
+done
+AC_SUBST(TEST_PYTHON)
+AM_CONDITIONAL([WANT_TWISTED_TESTS], test false != "$TEST_PYTHON")
 
 AC_ARG_ENABLE(cast-checks,      [  --disable-cast-checks         compile with GLIB cast checks disabled],[cchecks=${enableval}],cchecks=yes)
 if test "x$cchecks" = "xno"; then
@@ -225,6 +244,8 @@ mission-control.pc \
 server/Makefile \
 src/Makefile \
 test/Makefile \
+test/twisted/Makefile \
+test/twisted/tools/Makefile \
 tools/Makefile \
 util/Makefile \
 xml/Makefile \
diff --git a/test/Makefile.am b/test/Makefile.am
index 4a04ab0..4923486 100644
--- a/test/Makefile.am
+++ b/test/Makefile.am
@@ -5,6 +5,8 @@ INCLUDES = $(DBUS_CFLAGS) $(TELEPATHY_CFLAGS) -I$(top_srcdir) \
 
 if HAVE_TESTS
 
+SUBDIRS = twisted
+
 noinst_PROGRAMS = mc-client
 mc_client_SOURCES = mc-client.c
 mc_client_LDADD = $(top_builddir)/libmissioncontrol/libmissioncontrol-client.la
diff --git a/test/twisted/Makefile.am b/test/twisted/Makefile.am
new file mode 100644
index 0000000..021fa3b
--- /dev/null
+++ b/test/twisted/Makefile.am
@@ -0,0 +1,37 @@
+TWISTED_TESTS =
+
+TWISTED_BASIC_TESTS = \
+        test-basic.py
+
+TESTS =
+
+TESTS_ENVIRONMENT = \
+	PYTHONPATH=@abs_top_srcdir@/test/twisted:@abs_top_builddir@/test/twisted
+
+if WANT_TWISTED_TESTS
+  TWISTED_TESTS += $(TWISTED_BASIC_TESTS)
+endif
+
+check-local: check-twisted
+
+check-twisted:
+	$(MAKE) -C tools
+	rm -f tools/core
+	sh $(srcdir)/tools/with-session-bus.sh --config-file=tools/tmp-session-bus.conf -- $(MAKE) check-TESTS \
+		TESTS="$(TWISTED_TESTS)" \
+		TESTS_ENVIRONMENT="$(TESTS_ENVIRONMENT) $(TEST_PYTHON)"
+	@if test -e tools/core; then\
+		echo "Core dump exists: tools/core";\
+		exit 1;\
+	fi
+
+EXTRA_DIST = \
+	$(TWISTED_BASIC_TESTS) \
+	mctest.py \
+	servicetest.py
+
+CLEANFILES = mc-[1-9]*.log *.pyc */*.pyc
+
+check_misc_sources = $(TESTS)
+
+SUBDIRS = tools
diff --git a/test/twisted/README b/test/twisted/README
new file mode 100644
index 0000000..c9e23d1
--- /dev/null
+++ b/test/twisted/README
@@ -0,0 +1,26 @@
+To run Twisted tests:
+
+  make -C test/twisted check-twisted
+
+To run an individual Twisted test:
+
+  make -C test/twisted check-twisted TWISTED_TESTS=test-basic.py
+
+or:
+
+  cd test/twisted
+  sh tools/with-session-bus.sh --config-file=tools/tmp-session-bus.conf \
+        -- python test-basic.py
+
+To run with debug information:
+
+  make -C test/twisted check-twisted TWISTED_TESTS=test-basic.py \
+        CHECK_TWISTED_VERBOSE=1
+
+or:
+
+  cd test/twisted
+  sh tools/with-session-bus.sh --config-file=tools/tmp-session-bus.conf \
+        -- python test-basic.py -v
+
+
diff --git a/test/twisted/mctest.py b/test/twisted/mctest.py
new file mode 100644
index 0000000..88fd35b
--- /dev/null
+++ b/test/twisted/mctest.py
@@ -0,0 +1,88 @@
+
+"""
+Infrastructure code for testing Mission Control
+"""
+
+import base64
+import os
+import sha
+import sys
+
+import servicetest
+import twisted
+from twisted.internet import reactor
+
+import dbus
+
+def make_mc(bus, event_func, params=None):
+    default_params = {
+        }
+
+    if params:
+        default_params.update(params)
+
+    return servicetest.make_mc(bus, event_func, default_params)
+
+def install_colourer():
+    def red(s):
+        return '\x1b[31m%s\x1b[0m' % s
+
+    def green(s):
+        return '\x1b[32m%s\x1b[0m' % s
+
+    patterns = {
+        'handled': green,
+        'not handled': red,
+        }
+
+    class Colourer:
+        def __init__(self, fh, patterns):
+            self.fh = fh
+            self.patterns = patterns
+
+        def write(self, s):
+            f = self.patterns.get(s, lambda x: x)
+            self.fh.write(f(s))
+
+    sys.stdout = Colourer(sys.stdout, patterns)
+    return sys.stdout
+
+
+def exec_test_deferred (fun, params, protocol=None, timeout=None):
+    colourer = None
+
+    if sys.stdout.isatty():
+        colourer = install_colourer()
+
+    queue = servicetest.IteratingEventQueue(timeout)
+    queue.verbose = (
+        os.environ.get('CHECK_TWISTED_VERBOSE', '') != ''
+        or '-v' in sys.argv)
+
+    bus = dbus.SessionBus()
+    mc = make_mc(bus, queue.append, params)
+    error = None
+
+    try:
+        fun(queue, bus, mc)
+    except Exception, e:
+        import traceback
+        traceback.print_exc()
+        error = e
+
+    try:
+        if colourer:
+          sys.stdout = colourer.fh
+
+        if error is None:
+          reactor.callLater(0, reactor.stop)
+        else:
+          # please ignore the POSIX behind the curtain
+          os._exit(1)
+
+    except dbus.DBusException, e:
+        pass
+
+def exec_test(fun, params=None, protocol=None, timeout=None):
+  reactor.callWhenRunning (exec_test_deferred, fun, params, protocol, timeout)
+  reactor.run()
diff --git a/test/twisted/servicetest.py b/test/twisted/servicetest.py
new file mode 100644
index 0000000..8f26d64
--- /dev/null
+++ b/test/twisted/servicetest.py
@@ -0,0 +1,450 @@
+
+"""
+Infrastructure code for testing Mission Control
+"""
+
+from twisted.internet import glib2reactor
+from twisted.internet.protocol import Protocol, Factory, ClientFactory
+glib2reactor.install()
+
+import pprint
+import traceback
+import unittest
+
+import dbus.glib
+
+from twisted.internet import reactor
+
+tp_name_prefix = 'org.freedesktop.Telepathy'
+tp_path_prefix = '/org/freedesktop/Telepathy'
+
+class TryNextHandler(Exception):
+    pass
+
+def lazy(func):
+    def handler(event, data):
+        if func(event, data):
+            return True
+        else:
+            raise TryNextHandler()
+    handler.__name__ = func.__name__
+    return handler
+
+def match(type, **kw):
+    def decorate(func):
+        def handler(event, data, *extra, **extra_kw):
+            if event.type != type:
+                return False
+
+            for key, value in kw.iteritems():
+                if not hasattr(event, key):
+                    return False
+
+                if getattr(event, key) != value:
+                    return False
+
+            return func(event, data, *extra, **extra_kw)
+
+        handler.__name__ = func.__name__
+        return handler
+
+    return decorate
+
+class Event:
+    def __init__(self, type, **kw):
+        self.__dict__.update(kw)
+        self.type = type
+
+def format_event(event):
+    ret = ['- type %s' % event.type]
+
+    for key in dir(event):
+        if key != 'type' and not key.startswith('_'):
+            ret.append('- %s: %s' % (
+                key, pprint.pformat(getattr(event, key))))
+
+            if key == 'error':
+                ret.append('%s' % getattr(event, key))
+
+    return ret
+
+class EventTest:
+    """Somewhat odd event dispatcher for asynchronous tests.
+
+    Callbacks are kept in a queue. Incoming events are passed to the first
+    callback. If the callback returns True, the callback is removed. If the
+    callback raises AssertionError, the test fails. If there are no more
+    callbacks, the test passes. The reactor is stopped when the test passes.
+    """
+
+    def __init__(self):
+        self.queue = []
+        self.data = {'test': self}
+        self.timeout_delayed_call = reactor.callLater(5, self.timeout_cb)
+        #self.verbose = True
+        self.verbose = False
+        # ugh
+        self.stopping = False
+
+    def timeout_cb(self):
+        print 'timed out waiting for events'
+        print self.queue[0]
+        self.fail()
+
+    def fail(self):
+        # ugh; better way to stop the reactor and exit(1)?
+        import os
+        os._exit(1)
+
+    def expect(self, f):
+        self.queue.append(f)
+
+    def log(self, s):
+        if self.verbose:
+            print s
+
+    def try_stop(self):
+        if self.stopping:
+            return True
+
+        if not self.queue:
+            self.log('no handlers left; stopping')
+            self.stopping = True
+            reactor.stop()
+            return True
+
+        return False
+
+    def call_handlers(self, event):
+        self.log('trying %r' % self.queue[0])
+        handler = self.queue.pop(0)
+
+        try:
+            ret = handler(event, self.data)
+            if not ret:
+                self.queue.insert(0, handler)
+        except TryNextHandler, e:
+            if self.queue:
+                ret = self.call_handlers(event)
+            else:
+                ret = False
+            self.queue.insert(0, handler)
+
+        return ret
+
+    def handle_event(self, event):
+        if self.try_stop():
+            return
+
+        self.log('got event:')
+        self.log('- type: %s' % event.type)
+        map(self.log, format_event(event))
+
+        try:
+            ret = self.call_handlers(event)
+        except SystemExit, e:
+            if e.code:
+                print "Unsuccessful exit:", e
+                self.fail()
+            else:
+                self.queue[:] = []
+                ret = True
+        except AssertionError, e:
+            print 'test failed:'
+            traceback.print_exc()
+            self.fail()
+        except (Exception, KeyboardInterrupt), e:
+            print 'error in handler:'
+            traceback.print_exc()
+            self.fail()
+
+        if ret not in (True, False):
+            print ("warning: %s() returned something other than True or False"
+                % self.queue[0].__name__)
+
+        if ret:
+            self.timeout_delayed_call.reset(5)
+            self.log('event handled')
+        else:
+            self.log('event not handled')
+
+        self.log('')
+        self.try_stop()
+
+class EventPattern:
+    def __init__(self, type, **properties):
+        self.type = type
+        self.properties = properties
+
+    def match(self, event):
+        if event.type != self.type:
+            return False
+
+        for key, value in self.properties.iteritems():
+            try:
+                if getattr(event, key) != value:
+                    return False
+            except AttributeError:
+                return False
+
+        return True
+
+class TimeoutError(Exception):
+    pass
+
+class BaseEventQueue:
+    """Abstract event queue base class.
+
+    Implement the wait() method to have something that works.
+    """
+
+    def __init__(self, timeout=None):
+        self.verbose = False
+
+        if timeout is None:
+            self.timeout = 5
+        else:
+            self.timeout = timeout
+
+    def log(self, s):
+        if self.verbose:
+            print s
+
+    def expect(self, type, **kw):
+        pattern = EventPattern(type, **kw)
+
+        while True:
+            event = self.wait()
+            self.log('got event:')
+            map(self.log, format_event(event))
+
+            if pattern.match(event):
+                self.log('handled')
+                self.log('')
+                return event
+
+            self.log('not handled')
+            self.log('')
+
+    def expect_many(self, *patterns):
+        ret = [None] * len(patterns)
+
+        while None in ret:
+            event = self.wait()
+            self.log('got event:')
+            map(self.log, format_event(event))
+
+            for i, pattern in enumerate(patterns):
+                if pattern.match(event):
+                    self.log('handled')
+                    self.log('')
+                    ret[i] = event
+                    break
+            else:
+                self.log('not handled')
+                self.log('')
+
+        return ret
+
+    def demand(self, type, **kw):
+        pattern = EventPattern(type, **kw)
+
+        event = self.wait()
+        self.log('got event:')
+        map(self.log, format_event(event))
+
+        if pattern.match(event):
+            self.log('handled')
+            self.log('')
+            return event
+
+        self.log('not handled')
+        raise RuntimeError('expected %r, got %r' % (pattern, event))
+
+class IteratingEventQueue(BaseEventQueue):
+    """Event queue that works by iterating the Twisted reactor."""
+
+    def __init__(self, timeout=None):
+        BaseEventQueue.__init__(self, timeout)
+        self.events = []
+
+    def wait(self):
+        stop = [False]
+
+        def later():
+            stop[0] = True
+
+        delayed_call = reactor.callLater(self.timeout, later)
+
+        while (not self.events) and (not stop[0]):
+            reactor.iterate(0.1)
+
+        if self.events:
+            delayed_call.cancel()
+            return self.events.pop(0)
+        else:
+            raise TimeoutError
+
+    def append(self, event):
+        self.events.append(event)
+
+    # compatibility
+    handle_event = append
+
+class TestEventQueue(BaseEventQueue):
+    def __init__(self, events):
+        BaseEventQueue.__init__(self)
+        self.events = events
+
+    def wait(self):
+        if self.events:
+            return self.events.pop(0)
+        else:
+            raise TimeoutError
+
+class EventQueueTest(unittest.TestCase):
+    def test_expect(self):
+        queue = TestEventQueue([Event('foo'), Event('bar')])
+        assert queue.expect('foo').type == 'foo'
+        assert queue.expect('bar').type == 'bar'
+
+    def test_expect_many(self):
+        queue = TestEventQueue([Event('foo'), Event('bar')])
+        bar, foo = queue.expect_many(
+            EventPattern('bar'),
+            EventPattern('foo'))
+        assert bar.type == 'bar'
+        assert foo.type == 'foo'
+
+    def test_timeout(self):
+        queue = TestEventQueue([])
+        self.assertRaises(TimeoutError, queue.expect, 'foo')
+
+    def test_demand(self):
+        queue = TestEventQueue([Event('foo'), Event('bar')])
+        foo = queue.demand('foo')
+        assert foo.type == 'foo'
+
+    def test_demand_fail(self):
+        queue = TestEventQueue([Event('foo'), Event('bar')])
+        self.assertRaises(RuntimeError, queue.demand, 'bar')
+
+def unwrap(x):
+    """Hack to unwrap D-Bus values, so that they're easier to read when
+    printed."""
+
+    if isinstance(x, list):
+        return map(unwrap, x)
+
+    if isinstance(x, tuple):
+        return tuple(map(unwrap, x))
+
+    if isinstance(x, dict):
+        return dict([(unwrap(k), unwrap(v)) for k, v in x.iteritems()])
+
+    for t in [unicode, str, long, int, float, bool]:
+        if isinstance(x, t):
+            return t(x)
+
+    return x
+
+def call_async(test, proxy, method, *args, **kw):
+    """Call a D-Bus method asynchronously and generate an event for the
+    resulting method return/error."""
+
+    def reply_func(*ret):
+        test.handle_event(Event('dbus-return', method=method,
+            value=unwrap(ret)))
+
+    def error_func(err):
+        test.handle_event(Event('dbus-error', method=method, error=err))
+
+    method_proxy = getattr(proxy, method)
+    kw.update({'reply_handler': reply_func, 'error_handler': error_func})
+    method_proxy(*args, **kw)
+
+def sync_dbus(bus, q, conn):
+    # Dummy D-Bus method call
+    call_async(q, conn, "InspectHandles", 1, [])
+
+    event = q.expect('dbus-return', method='InspectHandles')
+
+class ProxyWrapper:
+    def __init__(self, object, default, others):
+        self.object = object
+        self.default_interface = dbus.Interface(object, default)
+        self.interfaces = dict([
+            (name, dbus.Interface(object, iface))
+            for name, iface in others.iteritems()])
+
+    def __getattr__(self, name):
+        if name in self.interfaces:
+            return self.interfaces[name]
+
+        if name in self.object.__dict__:
+            return getattr(self.object, name)
+
+        return getattr(self.default_interface, name)
+
+def make_mc(bus, event_func, params):
+    mc = bus.get_object(
+        tp_name_prefix + '.MissionControl',
+        tp_path_prefix + '/MissionControl')
+    assert mc is not None
+
+    bus.add_signal_receiver(
+        lambda *args, **kw:
+            event_func(
+                Event('dbus-signal',
+                    path=unwrap(kw['path']),
+                    signal=kw['member'], args=map(unwrap, args),
+                    interface=kw['interface'])),
+        None,       # signal name
+        None,       # interface
+        mc._named_service,
+        path_keyword='path',
+        member_keyword='member',
+        interface_keyword='interface',
+        byte_arrays=True
+        )
+
+    return mc
+
+def load_event_handlers():
+    path, _, _, _ = traceback.extract_stack()[0]
+    import compiler
+    import __main__
+    ast = compiler.parseFile(path)
+    return [
+        getattr(__main__, node.name)
+        for node in ast.node.asList()
+        if node.__class__ == compiler.ast.Function and
+            node.name.startswith('expect_')]
+
+class EventProtocol(Protocol):
+    def __init__(self, queue=None):
+        self.queue = queue
+
+    def dataReceived(self, data):
+        if self.queue is not None:
+            self.queue.handle_event(Event('socket-data', protocol=self,
+                data=data))
+
+    def sendData(self, data):
+        self.transport.write(data)
+
+class EventProtocolFactory(Factory):
+    def __init__(self, queue):
+        self.queue = queue
+
+    def buildProtocol(self, addr):
+        proto =  EventProtocol(self.queue)
+        self.queue.handle_event(Event('socket-connected', protocol=proto))
+        return proto
+
+class EventProtocolClientFactory(EventProtocolFactory, ClientFactory):
+    pass
+
+if __name__ == '__main__':
+    unittest.main()
+
diff --git a/test/twisted/test-basic.py b/test/twisted/test-basic.py
new file mode 100644
index 0000000..40febc2
--- /dev/null
+++ b/test/twisted/test-basic.py
@@ -0,0 +1,39 @@
+import dbus
+
+from mctest import exec_test
+
+def test(q, bus, mc):
+    # Introspect for debugging purpose
+    mc_introspected = mc.Introspect(
+            dbus_interface='org.freedesktop.DBus.Introspectable')
+    #print mc_introspected
+
+    # Check MC has D-Bus property interface
+    properties = mc.GetAll(
+            'org.freedesktop.Telepathy.AccountManager',
+            dbus_interface='org.freedesktop.DBus.Properties')
+    assert properties is not None
+
+    # Check the old iface
+    old_iface = dbus.Interface(mc, 'org.freedesktop.Telepathy.MissionControl')
+    arg0 = old_iface.GetOnlineConnections()
+    assert arg0 == []
+    arg0 = old_iface.GetPresence()
+    assert arg0 == 0, arg0
+
+    # Check MC has AccountManager interface
+    account_manager_iface = dbus.Interface(mc,
+            'org.freedesktop.Telepathy.AccountManager')
+
+    ## Not yet implemented in MC
+    #params = dbus.Dictionary({}, signature='sv')
+    #account_name = account_manager_iface.CreateAccount(
+    #        'salut', # Connection_Manager
+    #        'local-xmpp', # Protocol
+    #        'mc_test', #Display_Name
+    #        params, # Parameters
+    #        )
+    #assert account_name is not None
+
+if __name__ == '__main__':
+    exec_test(test, {})
diff --git a/test/twisted/tools/Makefile.am b/test/twisted/tools/Makefile.am
new file mode 100644
index 0000000..633fee9
--- /dev/null
+++ b/test/twisted/tools/Makefile.am
@@ -0,0 +1,32 @@
+exec-with-log.sh: exec-with-log.sh.in
+	sed -e "s|[@]abs_top_builddir[@]|@abs_top_builddir@|g" $< > $@
+	chmod +x $@
+
+%.conf: %.conf.in
+	sed -e "s|[@]abs_top_builddir[@]|@abs_top_builddir@|g" $< > $@
+
+# We don't use the full filename for the .in because > 99 character filenames
+# in tarballs are non-portable (and automake 1.8 doesn't let us build
+# non-archaic tarballs)
+org.freedesktop.Telepathy.%.service: %.service.in
+	sed -e "s|[@]abs_top_builddir[@]|@abs_top_builddir@|g" $< > $@
+
+# D-Bus service file for testing
+service_in_files = MissionControl.service.in
+service_files = org.freedesktop.Telepathy.MissionControl.service
+
+# D-Bus config file for testing
+conf_in_files = tmp-session-bus.conf.in
+conf_files = $(conf_in_files:.conf.in=.conf)
+
+BUILT_SOURCES = $(service_files) $(conf_files) exec-with-log.sh
+
+EXTRA_DIST = \
+	$(service_in_files) \
+	$(conf_in_files) \
+	exec-with-log.sh.in \
+	with-session-bus.sh
+
+CLEANFILES = \
+    $(BUILT_SOURCES) \
+    missioncontrol-testing.log
diff --git a/test/twisted/tools/MissionControl.service.in b/test/twisted/tools/MissionControl.service.in
new file mode 100644
index 0000000..dc33aa3
--- /dev/null
+++ b/test/twisted/tools/MissionControl.service.in
@@ -0,0 +1,3 @@
+[D-BUS Service]
+Name=org.freedesktop.Telepathy.MissionControl
+Exec=@abs_top_builddir@/test/twisted/tools/exec-with-log.sh
diff --git a/test/twisted/tools/exec-with-log.sh.in b/test/twisted/tools/exec-with-log.sh.in
new file mode 100644
index 0000000..dbda4bd
--- /dev/null
+++ b/test/twisted/tools/exec-with-log.sh.in
@@ -0,0 +1,15 @@
+#!/bin/sh
+
+cd "@abs_top_builddir@/test/twisted/tools"
+
+export MC_DEBUG=2
+ulimit -c unlimited
+exec > missioncontrol-testing.log 2>&1
+
+if test -n "$MISSIONCONTROL_TEST_VALGRIND"; then
+	export G_DEBUG=gc-friendly
+	export G_SLICE=always-malloc
+	MISSIONCONTROL_WRAPPER="valgrind --leak-check=full --num-callers=20"
+fi
+
+exec $MISSIONCONTROL_WRAPPER @abs_top_builddir@/server/mission-control
diff --git a/test/twisted/tools/tmp-session-bus.conf.in b/test/twisted/tools/tmp-session-bus.conf.in
new file mode 100644
index 0000000..5418ede
--- /dev/null
+++ b/test/twisted/tools/tmp-session-bus.conf.in
@@ -0,0 +1,30 @@
+<!-- This configuration file controls the per-user-login-session message bus.
+     Add a session-local.conf and edit that rather than changing this 
+     file directly. -->
+
+<!DOCTYPE busconfig PUBLIC "-//freedesktop//DTD D-Bus Bus Configuration 1.0//EN"
+ "http://www.freedesktop.org/standards/dbus/1.0/busconfig.dtd">
+<busconfig>
+  <!-- Our well-known bus type, don't change this -->
+  <type>session</type>
+
+  <listen>unix:tmpdir=/tmp</listen>
+
+  <servicedir>@abs_top_builddir@/test/twisted/tools</servicedir>
+
+  <policy context="default">
+    <!-- Allow everything to be sent -->
+    <allow send_destination="*"/>
+    <!-- Allow everything to be received -->
+    <allow eavesdrop="true"/>
+    <!-- Allow anyone to own anything -->
+    <allow own="*"/>
+  </policy>
+
+  <!-- This is included last so local configuration can override what's 
+       in this standard file -->
+  
+
+  
+
+</busconfig>
diff --git a/test/twisted/tools/with-session-bus.sh b/test/twisted/tools/with-session-bus.sh
new file mode 100644
index 0000000..519b9b1
--- /dev/null
+++ b/test/twisted/tools/with-session-bus.sh
@@ -0,0 +1,84 @@
+#!/bin/sh
+# with-session-bus.sh - run a program with a temporary D-Bus session daemon
+#
+# The canonical location of this program is the telepathy-glib tools/
+# directory, please synchronize any changes with that copy.
+#
+# Copyright (C) 2007-2008 Collabora Ltd. <http://www.collabora.co.uk/>
+#
+# 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.
+
+set -e
+
+me=with-session-bus
+
+dbus_daemon_args="--print-address=5 --print-pid=6 --fork"
+
+usage ()
+{
+  echo "usage: $me [options] -- program [program_options]" >&2
+  echo "Requires write access to the current directory." >&2
+  echo "" >&2
+  echo "If \$WITH_SESSION_BUS_FORK_DBUS_MONITOR is set, fork dbus-monitor" >&2
+  echo "with the arguments in \$WITH_SESSION_BUS_FORK_DBUS_MONITOR_OPT." >&2
+  echo "The output of dbus-monitor is saved in $me-<pid>.dbus-monitor-logs" >&2
+  exit 2
+}
+
+while test "z$1" != "z--"; do
+  case "$1" in
+  --session)
+    dbus_daemon_args="$dbus_daemon_args --session"
+    shift
+    ;;
+  --config-file=*)
+    # FIXME: assumes config file doesn't contain any special characters
+    dbus_daemon_args="$dbus_daemon_args $1"
+    shift
+    ;;
+  *)
+    usage
+    ;;
+  esac
+done
+shift
+if test "z$1" = "z"; then usage; fi
+
+exec 5> $me-$$.address
+exec 6> $me-$$.pid
+
+cleanup ()
+{
+  pid=`head -n1 $me-$$.pid`
+  if test -n "$pid" ; then
+    echo "Killing temporary bus daemon: $pid" >&2
+    kill -INT "$pid"
+  fi
+  rm -f $me-$$.address
+  rm -f $me-$$.pid
+}
+
+trap cleanup INT HUP TERM
+dbus-daemon $dbus_daemon_args
+
+{ echo -n "Temporary bus daemon is "; cat $me-$$.address; } >&2
+{ echo -n "Temporary bus daemon PID is "; head -n1 $me-$$.pid; } >&2
+
+e=0
+DBUS_SESSION_BUS_ADDRESS="`cat $me-$$.address`"
+export DBUS_SESSION_BUS_ADDRESS
+
+if [ -n "$WITH_SESSION_BUS_FORK_DBUS_MONITOR" ] ; then
+  echo -n "Forking dbus-monitor $WITH_SESSION_BUS_FORK_DBUS_MONITOR_OPT" >&2
+  dbus-monitor $WITH_SESSION_BUS_FORK_DBUS_MONITOR_OPT \
+        &> $me-$$.dbus-monitor-logs &
+fi
+
+"$@" || e=$?
+
+trap - INT HUP TERM
+cleanup
+
+exit $e
-- 
1.5.6.5




More information about the Telepathy-commits mailing list