~justin-fathomdb/nova/justinsb-openstack-api-volumes

« back to all changes in this revision

Viewing changes to vendor/Twisted-10.0.0/twisted/internet/test/reactormixins.py

  • Committer: Jesse Andrews
  • Date: 2010-05-28 06:05:26 UTC
  • Revision ID: git-v1:bf6e6e718cdc7488e2da87b21e258ccc065fe499
initial commit

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
# Copyright (c) 2008-2009 Twisted Matrix Laboratories.
 
2
# See LICENSE for details.
 
3
 
 
4
"""
 
5
Tests for implementations of L{IReactorTime}.
 
6
"""
 
7
 
 
8
__metaclass__ = type
 
9
 
 
10
import signal
 
11
 
 
12
from twisted.internet.defer import TimeoutError
 
13
from twisted.trial.unittest import TestCase, SkipTest
 
14
from twisted.python.runtime import platformType
 
15
from twisted.python.reflect import namedAny
 
16
from twisted.python import log
 
17
from twisted.python.failure import Failure
 
18
 
 
19
# Access private APIs.
 
20
if platformType == 'posix':
 
21
    from twisted.internet import process
 
22
else:
 
23
    process = None
 
24
 
 
25
 
 
26
class ReactorBuilder:
 
27
    """
 
28
    L{TestCase} mixin which provides a reactor-creation API.  This mixin
 
29
    defines C{setUp} and C{tearDown}, so mix it in before L{TestCase} or call
 
30
    its methods from the overridden ones in the subclass.
 
31
 
 
32
    @cvar skippedReactors: A dict mapping FQPN strings of reactors for
 
33
        which the tests defined by this class will be skipped to strings
 
34
        giving the skip message.
 
35
    @cvar requiredInterfaces: A C{list} of interfaces which the reactor must
 
36
        provide or these tests will be skipped.  The default, C{None}, means
 
37
        that no interfaces are required.
 
38
    @ivar reactorFactory: A no-argument callable which returns the reactor to
 
39
        use for testing.
 
40
    @ivar originalHandler: The SIGCHLD handler which was installed when setUp
 
41
        ran and which will be re-installed when tearDown runs.
 
42
    @ivar _reactors: A list of FQPN strings giving the reactors for which
 
43
        TestCases will be created.
 
44
    """
 
45
 
 
46
    _reactors = ["twisted.internet.selectreactor.SelectReactor",
 
47
                 "twisted.internet.pollreactor.PollReactor",
 
48
                 "twisted.internet.epollreactor.EPollReactor",
 
49
                 "twisted.internet.glib2reactor.Glib2Reactor",
 
50
                 "twisted.internet.gtk2reactor.Gtk2Reactor",
 
51
                 "twisted.internet.kqueuereactor.KQueueReactor",
 
52
                 "twisted.internet.win32eventreactor.Win32Reactor",
 
53
                 "twisted.internet.iocpreactor.reactor.IOCPReactor"]
 
54
 
 
55
    reactorFactory = None
 
56
    originalHandler = None
 
57
    requiredInterface = None
 
58
    skippedReactors = {}
 
59
 
 
60
    def setUp(self):
 
61
        """
 
62
        Clear the SIGCHLD handler, if there is one, to ensure an environment
 
63
        like the one which exists prior to a call to L{reactor.run}.
 
64
        """
 
65
        if platformType == 'posix':
 
66
            self.originalHandler = signal.signal(signal.SIGCHLD, signal.SIG_DFL)
 
67
 
 
68
 
 
69
    def tearDown(self):
 
70
        """
 
71
        Restore the original SIGCHLD handler and reap processes as long as
 
72
        there seem to be any remaining.
 
73
        """
 
74
        if self.originalHandler is not None:
 
75
            signal.signal(signal.SIGCHLD, self.originalHandler)
 
76
        if process is not None:
 
77
            while process.reapProcessHandlers:
 
78
                log.msg(
 
79
                    "ReactorBuilder.tearDown reaping some processes %r" % (
 
80
                        process.reapProcessHandlers,))
 
81
                process.reapAllProcesses()
 
82
 
 
83
 
 
84
    def unbuildReactor(self, reactor):
 
85
        """
 
86
        Clean up any resources which may have been allocated for the given
 
87
        reactor by its creation or by a test which used it.
 
88
        """
 
89
        # Chris says:
 
90
        #
 
91
        # XXX These explicit calls to clean up the waker (and any other
 
92
        # internal readers) should become obsolete when bug #3063 is
 
93
        # fixed. -radix, 2008-02-29. Fortunately it should probably cause an
 
94
        # error when bug #3063 is fixed, so it should be removed in the same
 
95
        # branch that fixes it.
 
96
        #
 
97
        # -exarkun
 
98
        if getattr(reactor, '_internalReaders', None) is not None:
 
99
            for reader in reactor._internalReaders:
 
100
                reactor.removeReader(reader)
 
101
                reader.connectionLost(None)
 
102
            reactor._internalReaders.clear()
 
103
 
 
104
        # Here's an extra thing unrelated to wakers but necessary for
 
105
        # cleaning up after the reactors we make.  -exarkun
 
106
        reactor.disconnectAll()
 
107
 
 
108
        # It would also be bad if any timed calls left over were allowed to
 
109
        # run.
 
110
        calls = reactor.getDelayedCalls()
 
111
        for c in calls:
 
112
            c.cancel()
 
113
 
 
114
 
 
115
    def buildReactor(self):
 
116
        """
 
117
        Create and return a reactor using C{self.reactorFactory}.
 
118
        """
 
119
        try:
 
120
            reactor = self.reactorFactory()
 
121
        except:
 
122
            # Unfortunately, not all errors which result in a reactor being
 
123
            # unusable are detectable without actually instantiating the
 
124
            # reactor.  So we catch some more here and skip the test if
 
125
            # necessary.
 
126
            raise SkipTest(Failure().getErrorMessage())
 
127
        else:
 
128
            if self.requiredInterface is not None:
 
129
                if not self.requiredInterface.providedBy(reactor):
 
130
                    self.unbuildReactor(reactor)
 
131
                    raise SkipTest(
 
132
                        "%r does not provide %r" % (
 
133
                            reactor, self.requiredInterface))
 
134
        self.addCleanup(self.unbuildReactor, reactor)
 
135
        return reactor
 
136
 
 
137
 
 
138
    def runReactor(self, reactor, timeout=None):
 
139
        """
 
140
        Run the reactor for at most the given amount of time.
 
141
 
 
142
        @param reactor: The reactor to run.
 
143
 
 
144
        @type timeout: C{int} or C{float}
 
145
        @param timeout: The maximum amount of time, specified in seconds, to
 
146
            allow the reactor to run.  If the reactor is still running after
 
147
            this much time has elapsed, it will be stopped and an exception
 
148
            raised.  If C{None}, the default test method timeout imposed by
 
149
            Trial will be used.  This depends on the L{IReactorTime}
 
150
            implementation of C{reactor} for correct operation.
 
151
 
 
152
        @raise TimeoutError: If the reactor is still running after C{timeout}
 
153
            seconds.
 
154
        """
 
155
        if timeout is None:
 
156
            timeout = self.getTimeout()
 
157
 
 
158
        timedOut = []
 
159
        def stop():
 
160
            timedOut.append(None)
 
161
            reactor.stop()
 
162
 
 
163
        reactor.callLater(timeout, stop)
 
164
        reactor.run()
 
165
        if timedOut:
 
166
            raise TimeoutError(
 
167
                "reactor still running after %s seconds" % (timeout,))
 
168
 
 
169
 
 
170
    def makeTestCaseClasses(cls):
 
171
        """
 
172
        Create a L{TestCase} subclass which mixes in C{cls} for each known
 
173
        reactor and return a dict mapping their names to them.
 
174
        """
 
175
        classes = {}
 
176
        for reactor in cls._reactors:
 
177
            shortReactorName = reactor.split(".")[-1]
 
178
            name = (cls.__name__ + "." + shortReactorName).replace(".", "_")
 
179
            class testcase(cls, TestCase):
 
180
                __module__ = cls.__module__
 
181
                if reactor in cls.skippedReactors:
 
182
                    skip = cls.skippedReactors[reactor]
 
183
                try:
 
184
                    reactorFactory = namedAny(reactor)
 
185
                except:
 
186
                    skip = Failure().getErrorMessage()
 
187
            testcase.__name__ = name
 
188
            classes[testcase.__name__] = testcase
 
189
        return classes
 
190
    makeTestCaseClasses = classmethod(makeTestCaseClasses)
 
191
 
 
192
 
 
193
__all__ = ['ReactorBuilder']