Skip to content

Commit

Permalink
Merge pull request #19 from zerodb/master
Browse files Browse the repository at this point in the history
AttributeError 'server' when StorageServer creation fails

Thanks!
  • Loading branch information
jimfulton committed Jan 12, 2017
2 parents 79bc64e + 2bb9e89 commit c0667b8
Show file tree
Hide file tree
Showing 3 changed files with 154 additions and 1 deletion.
3 changes: 3 additions & 0 deletions CHANGES.rst
Original file line number Diff line number Diff line change
Expand Up @@ -180,6 +180,9 @@ Dropped features:

- Drop support for Python 2.6 and 3.2.

- Fix AttributeError: 'ZEOServer' object has no attribute 'server' when
StorageServer creation fails.

4.2.0b1 (2015-06-05)
--------------------

Expand Down
7 changes: 6 additions & 1 deletion src/ZEO/runzeo.py
Original file line number Diff line number Diff line change
Expand Up @@ -141,6 +141,7 @@ class ZEOServer:

def __init__(self, options):
self.options = options
self.server = None

def main(self):
self.setup_default_logging()
Expand All @@ -153,7 +154,7 @@ def main(self):
self.create_server()
self.loop_forever()
finally:
self.server.close()
self.close_server()
self.clear_socket()
self.remove_pidfile()

Expand Down Expand Up @@ -254,6 +255,10 @@ def loop_forever(self):
else:
self.server.loop()

def close_server(self):
if self.server is not None:
self.server.close()

def handle_sigterm(self):
log("terminated by SIGTERM")
sys.exit(0)
Expand Down
145 changes: 145 additions & 0 deletions src/ZEO/tests/testZEOServer.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,145 @@
#
# Fix AttributeError: 'ZEOServer' object has no attribute 'server' in
# ZEOServer.main
#
import unittest

from ZEO.runzeo import ZEOServer


class TestStorageServer:

def __init__(self, fail_create_server):
self.called = []
if fail_create_server: raise RuntimeError()

def close(self):
self.called.append("close")


class TestZEOServer(ZEOServer):

def __init__(self, fail_create_server=False, fail_loop_forever=False):
ZEOServer.__init__(self, None)
self.called = []
self.fail_create_server = fail_create_server
self.fail_loop_forever = fail_loop_forever

def setup_default_logging(self):
self.called.append("setup_default_logging")

def check_socket(self):
self.called.append("check_socket")

def clear_socket(self):
self.called.append("clear_socket")

def make_pidfile(self):
self.called.append("make_pidfile")

def open_storages(self):
self.called.append("open_storages")

def setup_signals(self):
self.called.append("setup_signals")

def create_server(self):
self.called.append("create_server")
self.server = TestStorageServer(self.fail_create_server)

def loop_forever(self):
self.called.append("loop_forever")
if self.fail_loop_forever: raise RuntimeError()

def close_server(self):
self.called.append("close_server")
ZEOServer.close_server(self)

def clear_socket(self):
self.called.append("clear_socket")

def remove_pidfile(self):
self.called.append("remove_pidfile")


class AttributeErrorTests(unittest.TestCase):

def testFailCreateServer(self):
# Demonstrate the AttributeError
zeo = TestZEOServer(fail_create_server=True)
self.assertRaises(RuntimeError, zeo.main)


class CloseServerTests(unittest.TestCase):

def testCallSequence(self):
# The close_server hook is called after loop_forever
# has returned
zeo = TestZEOServer()
zeo.main()
self.assertEqual(zeo.called, [
"setup_default_logging",
"check_socket",
"clear_socket",
"make_pidfile",
"open_storages",
"setup_signals",
"create_server",
"loop_forever",
"close_server", # New
"clear_socket",
"remove_pidfile",
])
# The default implementation closes the storage server
self.assertEqual(hasattr(zeo, "server"), True)
self.assertEqual(zeo.server.called, ["close"])

def testFailLoopForever(self):
# The close_server hook is called if loop_forever exits
# with an exception
zeo = TestZEOServer(fail_loop_forever=True)
self.assertRaises(RuntimeError, zeo.main)
self.assertEqual(zeo.called, [
"setup_default_logging",
"check_socket",
"clear_socket",
"make_pidfile",
"open_storages",
"setup_signals",
"create_server",
"loop_forever",
"close_server",
"clear_socket",
"remove_pidfile",
])
# The storage server has been closed
self.assertEqual(hasattr(zeo, "server"), True)
self.assertEqual(zeo.server.called, ["close"])

def testFailCreateServer(self):
# The close_server hook is called if create_server exits
# with an exception
zeo = TestZEOServer(fail_create_server=True)
self.assertRaises(RuntimeError, zeo.main)
self.assertEqual(zeo.called, [
"setup_default_logging",
"check_socket",
"clear_socket",
"make_pidfile",
"open_storages",
"setup_signals",
"create_server",
"close_server",
"clear_socket",
"remove_pidfile",
])
# The server attribute is present but None
self.assertEqual(hasattr(zeo, "server"), True)
self.assertEqual(zeo.server, None)


def test_suite():
suite = unittest.TestSuite()
suite.addTest(unittest.makeSuite(AttributeErrorTests))
suite.addTest(unittest.makeSuite(CloseServerTests))
return suite

0 comments on commit c0667b8

Please sign in to comment.