[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