summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorPatrick Ohly <patrick.ohly@intel.com>2012-05-08 09:42:45 +0200
committerPatrick Ohly <patrick.ohly@intel.com>2012-05-10 22:08:49 +0200
commit98ed8d10460f434d382487d80474ab14ab5df8a4 (patch)
treef3edb6bc67b3c48fb71dbff531989bc19c5cb21c
parent5423a1fefb3fd00b1ed1ddab149360742e7afd3c (diff)
D-Bus testing: cover killing of syncevo-dbus-server
TestLocalSync.testParentFailure covers the situation that syncevo-dbus-server is killed while syncevo-dbus-helper and syncevo-local-sync are waiting for a password. With syncevo-dbus-server gone, they'll never get that information and need to abort syncing. When running syncevo-dbus-server under valgrindcheck.sh, both the wrapper script and the actual syncevo-dbus-server must be killed, starting with the wrapper script because otherwise it'll initiate a shutdown when it sees the death of the syncevo-dbus-server. The test-dbus.py infrastructure needs to be improved for this: - allow removing DBusUtil.pserver during a test - collect zombies after running a test - kill syncevo-dbus-helper and syncevo-local-sync Instead of killing a known list of processes, it might be better to kill all children of test-dbus.py.
-rwxr-xr-xtest/test-dbus.py102
1 files changed, 94 insertions, 8 deletions
diff --git a/test/test-dbus.py b/test/test-dbus.py
index 801fcef1..5ca8ec63 100755
--- a/test/test-dbus.py
+++ b/test/test-dbus.py
@@ -22,6 +22,7 @@ import unittest
import subprocess
import time
import os
+import errno
import signal
import shutil
import copy
@@ -403,9 +404,17 @@ class DBusUtil(Timeout):
DBusUtil.quit_events = []
DBusUtil.reply = None
- kill = subprocess.Popen("sh -c 'killall -9 syncevo-dbus-server dbus-monitor >/dev/null 2>&1'", shell=True)
+ kill = subprocess.Popen("sh -c 'killall -9 syncevo-dbus-server syncevo-local-sync syncevo-dbus-helper dbus-monitor >/dev/null 2>&1'", shell=True)
kill.communicate()
+ # collect zombies
+ try:
+ while os.waitpid(-1, os.WNOHANG)[0]:
+ pass
+ except OSError, ex:
+ if ex.errno != errno.ECHILD:
+ raise ex
+
"""own_xdg is saved in self for we use this flag to check whether
to copy the reference directory tree."""
self.own_xdg = own_xdg
@@ -535,7 +544,7 @@ class DBusUtil(Timeout):
delay = 60
else:
delay = 20
- if not ShutdownSubprocess(DBusUtil.pserver, delay):
+ if DBusUtil.pserver and not ShutdownSubprocess(DBusUtil.pserver, delay):
print " syncevo-dbus-server had to be killed with SIGKILL"
result.errors.append((self,
"syncevo-dbus-server had to be killed with SIGKILL"))
@@ -562,7 +571,8 @@ class DBusUtil(Timeout):
# detect the expected "killed by signal TERM" both when
# running syncevo-dbus-server directly (negative value) and
# when valgrindcheck.sh returns the error code 128 + 15 = 143
- if DBusUtil.pserver.returncode and \
+ if DBusUtil.pserver and \
+ DBusUtil.pserver.returncode and \
DBusUtil.pserver.returncode != 128 + 15 and \
DBusUtil.pserver.returncode != -15:
# create a new failure specifically for the server
@@ -590,7 +600,7 @@ class DBusUtil(Timeout):
# must be syncevo-dbus-server
res = match.group(1)
if 'syncevo-dbus-server' in res:
- return res
+ return (res, pid)
# not found, try children
for process in os.listdir('/proc'):
try:
@@ -604,13 +614,20 @@ class DBusUtil(Timeout):
# ignore all errors
pass
# no result
- return ""
+ return None
def serverExecutable(self):
"""returns full path of currently running syncevo-dbus-server binary"""
res = self.serverExecutableHelper(DBusUtil.pserver.pid)
self.assertTrue(res)
- return res
+ return res[0]
+
+ def serverPid(self):
+ """PID of syncevo-dbus-server, None if not running. Works regardless whether it is
+ started directly or with a wrapper script like valgrindcheck.sh."""
+ res = self.serverExecutableHelper(DBusUtil.pserver.pid)
+ self.assertTrue(res)
+ return res[1]
def setUpServer(self):
self.server = dbus.Interface(bus.get_object('org.syncevolution',
@@ -3338,6 +3355,9 @@ class TestMultipleConfigs(unittest.TestCase, DBusUtil):
class TestLocalSync(unittest.TestCase, DBusUtil):
"""Tests involving local sync."""
+ def run(self, result):
+ self.runTest(result)
+
def setUp(self):
self.setUpServer()
@@ -3426,8 +3446,74 @@ END:VCARD''')
self.assertNotIn("error", report) # ... but without error message
self.assertEqual(report["source-addressbook-status"], "0") # unknown status for source (aborted early)
- def run(self, result):
- self.runTest(result)
+ @timeout(200)
+ def testParentFailure(self):
+ """TestLocalSync.testParentFailure - check that child detects when parent dies"""
+ self.setUpConfigs(childPassword="-")
+ self.setUpListeners(self.sessionpath)
+ self.lastState = "unknown"
+ pid = self.serverPid()
+ serverPid = DBusUtil.pserver.pid
+ def infoRequest(id, session, state, handler, type, params):
+ if state == "request":
+ self.assertEqual(self.lastState, "unknown")
+ self.lastState = "request"
+ # kill syncevo-dbus-server
+ if pid != serverPid:
+ logging.printf('killing syncevo-dbus-server wrapper with pid %d', serverPid)
+ os.kill(serverPid, signal.SIGKILL)
+ logging.printf('killing syncevo-dbus-server with pid %d', pid)
+ os.kill(pid, signal.SIGKILL)
+ loop.quit()
+ dbusSignal = bus.add_signal_receiver(infoRequest,
+ 'InfoRequest',
+ 'org.syncevolution.Server',
+ self.server.bus_name,
+ None,
+ byte_arrays=True,
+ utf8_strings=True)
+
+ try:
+ self.session.Sync("slow", {})
+ loop.run()
+ finally:
+ dbusSignal.remove()
+
+ # Remove syncevo-dbus-server zombie process(es).
+ try:
+ while os.waitpid(-1, os.WNOHANG)[0]:
+ pass
+ except OSError, ex:
+ if ex.errno != errno.ECHILD:
+ raise ex
+ DBusUtil.pserver = None
+
+ # Give syncevo-dbus-helper and syncevo-local-sync some time to shut down.
+ time.sleep(usingValgrind() and 60 or 10)
+
+ # Now no processes should be left in the process group
+ # of the syncevo-dbus-server.
+ ps = subprocess.Popen(['ps', 'x', '--no-headers', '-o', 'pgid,pid,args'],
+ stdout=subprocess.PIPE,
+ stderr=subprocess.PIPE)
+ out, err = ps.communicate()
+ self.assertEqual('', err)
+ children = []
+ for line in out.splitlines():
+ pgid, command = line.lstrip().split(' ', 1)
+ if int(pgid) == pid:
+ children.append(command)
+ self.assertEqual([], children)
+
+ # try:
+ # os.kill(-pid, signal.SIGTERM)
+ # self.fail('found some unexpected child process of syncevo-dbus-server')
+ # except OSError, ex:
+ # if ex.errno != errno.ECHILD:
+ # raise ex
+
+ # TODO: test that password timeout and password cancelation are
+ # correctly recognized during a sync
class TestFileNotify(unittest.TestCase, DBusUtil):
"""syncevo-dbus-server must stop if one of its files mapped into