22
22
__metaclass__ = type
25
'BaseLayer', 'DatabaseLayer', 'LibrarianLayer', 'FunctionalLayer',
26
'LaunchpadLayer', 'ZopelessLayer', 'LaunchpadFunctionalLayer',
27
'LaunchpadZopelessLayer', 'LaunchpadScriptLayer', 'PageTestLayer',
28
'LayerConsistencyError', 'LayerIsolationError', 'TwistedLayer',
29
'ExperimentalLaunchpadZopelessLayer', 'TwistedLaunchpadZopelessLayer'
27
'ExperimentalLaunchpadZopelessLayer',
29
'LaunchpadFunctionalLayer',
31
'LaunchpadScriptLayer',
32
'LaunchpadZopelessLayer',
33
'LayerIsolationError',
36
'TwistedLaunchpadZopelessLayer',
38
from textwrap import dedent
52
from textwrap import dedent
41
53
from unittest import TestCase, TestResult
42
54
from urllib import urlopen
133
def wait_children(seconds=120):
134
"""Wait for all children to exit.
136
:param seconds: Maximum number of seconds to wait. If None, wait
139
now = datetime.datetime.now
143
until = now() + datetime.timedelta(seconds=seconds)
146
os.waitpid(-1, os.WNOHANG)
147
except OSError, error:
148
if error.errno != errno.ECHILD:
151
if until is not None and now() > until:
162
195
# Store currently running threads so we can detect if a test
163
196
# leaves new threads running.
164
197
BaseLayer._threads = threading.enumerate()
166
198
BaseLayer.check()
168
199
BaseLayer.original_working_directory = os.getcwd()
170
201
# Tests and test infrastruture sometimes needs to know the test
199
229
os.chdir(BaseLayer.original_working_directory)
201
231
BaseLayer.original_working_directory = None
205
233
del canonical.launchpad.mail.stub.test_emails[:]
207
234
BaseLayer.test_name = None
209
235
BaseLayer.check()
211
237
# Check for tests that leave live threads around early.
212
238
# A live thread may be the cause of other failures, such as
213
239
# uncollectable garbage.
215
thread for thread in threading.enumerate()
216
if thread not in BaseLayer._threads and thread.isAlive()]
241
thread for thread in threading.enumerate()
242
if thread not in BaseLayer._threads and thread.isAlive()
218
246
BaseLayer.flagTestIsolationFailure(
219
"Test left new live threads: %s" % repr(new_threads))
247
"Test left new live threads: %s" % repr(new_threads))
220
248
del BaseLayer._threads
222
250
# Objects with __del__ methods cannot participate in refence cycles.
242
270
if FunctionalLayer.isSetUp and ZopelessLayer.isSetUp:
243
271
raise LayerInvariantError(
244
"Both Zopefull and Zopeless CA environments setup"
272
"Both Zopefull and Zopeless CA environments setup")
247
274
# Detect a test that causes the component architecture to be loaded.
248
275
# This breaks test isolation, as it cannot be torn down.
249
if (is_ca_available() and not FunctionalLayer.isSetUp
250
and not ZopelessLayer.isSetUp):
276
if (is_ca_available()
277
and not FunctionalLayer.isSetUp
278
and not ZopelessLayer.isSetUp):
251
279
raise LayerIsolationError(
252
280
"Component architecture should not be loaded by tests. "
253
281
"This should only be loaded by the Layer."
258
286
# but it is better for the tear down to be explicit.
259
287
if ZopelessTransactionManager._installed is not None:
260
288
raise LayerIsolationError(
261
"Zopeless environment was setup and not torn down."
289
"Zopeless environment was setup and not torn down.")
264
291
# Detect a test that forgot to reset the default socket timeout.
265
292
# This safety belt is cheap and protects us from very nasty
1073
1100
class TwistedLaunchpadZopelessLayer(TwistedLayer, LaunchpadZopelessLayer):
1074
1101
"""A layer for cleaning up the Twisted thread pool."""
1104
class AppServerLayer(LaunchpadLayer):
1105
"""Environment for starting and stopping the app server."""
1107
services = ('librarian', 'restricted-librarian')
1108
LPCONFIG = 'testrunner-appserver'
1116
os.execlp('make', 'make', '-i' '-s', 'LPCONFIG=%s' % cls.LPCONFIG,
1117
'run_all_quickly_and_quietly')
1118
# Should never get here...
1120
# The parent. Wait until the app server is responsive, but not
1121
# forever. Make sure the test database is set up.
1122
from canonical.launchpad.ftests.harness import LaunchpadTestSetup
1123
LaunchpadTestSetup().setUp()
1124
until = time.time() + 60
1125
while time.time() < until:
1127
connection = urlopen('http://launchpad.dev:8085')
1129
except IOError, (error_message, error):
1130
if error.args[0] != errno.ECONNREFUSED:
1137
cls.stopAllServices()
1142
# Force the database to reset.
1143
from canonical.launchpad.ftests.harness import LaunchpadTestSetup
1144
LaunchpadTestSetup().tearDown()
1145
cls.stopAllServices()
1146
# Ensure that there are no child processes still running.
1148
os.waitpid(-1, os.WNOHANG)
1149
except OSError, error:
1150
if error.errno != errno.ECHILD:
1153
cls.stopAllServices()
1154
raise LayerIsolationError('Child processes have leaked through.')
1163
def testTearDown(cls):
1164
DatabaseLayer.force_dirty_database()
1168
def stopAllServices(cls):
1169
os.system('make -i -s LPCONFIG=%s stop_quickly_and_quietly'