Skip to content

Commit

Permalink
Merge pull request twisted#891 from twisted/iservice-parent-7922
Browse files Browse the repository at this point in the history
[twisted#7922] Add parent to IService
  • Loading branch information
moshez authored Jan 9, 2018
2 parents 59af90d + 15bf322 commit 3bd48ac
Show file tree
Hide file tree
Showing 4 changed files with 168 additions and 5 deletions.
14 changes: 9 additions & 5 deletions src/twisted/application/service.py
Original file line number Diff line number Diff line change
Expand Up @@ -92,13 +92,17 @@ class IService(Interface):
A service.
Run start-up and shut-down code at the appropriate times.
@type name: C{string}
@ivar name: The name of the service (or None)
@type running: C{boolean}
@ivar running: Whether the service is running.
"""

name = Attribute(
"A C{str} which is the name of the service or C{None}.")

running = Attribute(
"A C{boolean} which indicates whether the service is running.")

parent = Attribute(
"An C{IServiceCollection} which is the parent or C{None}.")

def setName(name):
"""
Set the name of the service.
Expand Down
155 changes: 155 additions & 0 deletions src/twisted/application/test/test_service.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,14 +7,169 @@

from __future__ import absolute_import, division

from zope.interface import implementer
from zope.interface.exceptions import BrokenImplementation
from zope.interface.verify import verifyObject

from twisted.persisted.sob import IPersistable
from twisted.application.service import Application, IProcess
from twisted.application.service import IService, IServiceCollection
from twisted.application.service import Service
from twisted.trial.unittest import TestCase


@implementer(IService)
class AlmostService(object):
"""
Implement IService in a way that can fail.
In general, classes should maintain invariants that adhere
to the interfaces that they claim to implement --
otherwise, it is a bug.
This is a buggy class -- the IService implementation is fragile,
and several methods will break it. These bugs are intentional,
as the tests trigger them -- and then check that the class,
indeed, no longer complies with the interface (IService)
that it claims to comply with.
Since the verification will, by definition, only fail on buggy classes --
in other words, those which do not actually support the interface they
claim to support, we have to write a buggy class to properly verify
the interface.
"""

def __init__(self, name, parent, running):
self.name = name
self.parent = parent
self.running = running


def makeInvalidByDeletingName(self):
"""
Probably not a wise method to call.
This method removes the :code:`name` attribute,
which has to exist in IService classes.
"""
del self.name


def makeInvalidByDeletingParent(self):
"""
Probably not a wise method to call.
This method removes the :code:`parent` attribute,
which has to exist in IService classes.
"""
del self.parent


def makeInvalidByDeletingRunning(self):
"""
Probably not a wise method to call.
This method removes the :code:`running` attribute,
which has to exist in IService classes.
"""
del self.running


def setName(self, name):
"""
See L{twisted.application.service.IService}.
@param name: ignored
"""


def setServiceParent(self, parent):
"""
See L{twisted.application.service.IService}.
@param parent: ignored
"""


def disownServiceParent(self):
"""
See L{twisted.application.service.IService}.
"""


def privilegedStartService(self):
"""
See L{twisted.application.service.IService}.
"""


def startService(self):
"""
See L{twisted.application.service.IService}.
"""


def stopService(self):
"""
See L{twisted.application.service.IService}.
"""



class ServiceInterfaceTests(TestCase):
"""
Tests for L{twisted.application.service.IService} implementation.
"""
def setUp(self):
"""
Build something that implements IService.
"""
self.almostService = AlmostService(parent=None, running=False,
name=None)


def test_realService(self):
"""
Service implements IService.
"""
myService = Service()
verifyObject(IService, myService)


def test_hasAll(self):
"""
AlmostService implements IService.
"""
verifyObject(IService, self.almostService)


def test_noName(self):
"""
AlmostService with no name does not implement IService.
"""
self.almostService.makeInvalidByDeletingName()
with self.assertRaises(BrokenImplementation):
verifyObject(IService, self.almostService)


def test_noParent(self):
"""
AlmostService with no parent does not implement IService.
"""
self.almostService.makeInvalidByDeletingParent()
with self.assertRaises(BrokenImplementation):
verifyObject(IService, self.almostService)


def test_noRunning(self):
"""
AlmostService with no running does not implement IService.
"""
self.almostService.makeInvalidByDeletingRunning()
with self.assertRaises(BrokenImplementation):
verifyObject(IService, self.almostService)



class ApplicationTests(TestCase):
"""
Expand Down
1 change: 1 addition & 0 deletions src/twisted/newsfragments/7922.bugfix
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
twisted.application.service.IService is now documented as requiring the 'running', 'name' and 'parent' attributes (the documentation previously implied they were required, but was unclear).
3 changes: 3 additions & 0 deletions src/twisted/test/test_twistd.py
Original file line number Diff line number Diff line change
Expand Up @@ -609,6 +609,9 @@ def removePID(self, pidfile):
@implementer(service.IService, service.IProcess)
class FakeService(object):

parent = None
running = None
name = None
processName = None
uid = None
gid = None
Expand Down

0 comments on commit 3bd48ac

Please sign in to comment.