Merge lp:~lifeless/launchpad/fixtures into lp:launchpad

Proposed by Robert Collins
Status: Merged
Approved by: Michael Hudson-Doyle
Approved revision: no longer in the source branch.
Merged at revision: 11736
Proposed branch: lp:~lifeless/launchpad/fixtures
Merge into: lp:launchpad
Diff against target: 359 lines (+11/-274)
4 files modified
lib/lp/poppy/tests/test_poppy.py (+3/-3)
lib/lp/testing/__init__.py (+1/-15)
lib/lp/testing/fixture.py (+7/-118)
lib/lp/testing/tests/test_fixture.py (+0/-138)
To merge this branch: bzr merge lp:~lifeless/launchpad/fixtures
Reviewer Review Type Date Requested Status
Michael Hudson-Doyle Approve
Review via email: mp+38668@code.launchpad.net

Commit message

Cleanup some partially-migrated-from test support code.

Description of the change

Cleanup some partially-migrated-from test support code.

To post a comment you must log in.
Revision history for this message
Michael Hudson-Doyle (mwhudson) wrote :

Looks nice, thanks!

review: Approve

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
=== modified file 'lib/lp/poppy/tests/test_poppy.py'
--- lib/lp/poppy/tests/test_poppy.py 2010-09-28 22:33:42 +0000
+++ lib/lp/poppy/tests/test_poppy.py 2010-10-17 21:28:46 +0000
@@ -49,7 +49,7 @@
49 self.root_dir, port=self.port, cmd='echo CLOSED')49 self.root_dir, port=self.port, cmd='echo CLOSED')
50 self.poppy.startPoppy()50 self.poppy.startPoppy()
5151
52 def tearDown(self):52 def cleanUp(self):
53 self.poppy.killPoppy()53 self.poppy.killPoppy()
5454
55 def getTransport(self):55 def getTransport(self):
@@ -129,7 +129,7 @@
129 self._tac = PoppyTac(self.root_dir)129 self._tac = PoppyTac(self.root_dir)
130 self._tac.setUp()130 self._tac.setUp()
131131
132 def tearDown(self):132 def cleanUp(self):
133 shutil.rmtree(self._home_dir)133 shutil.rmtree(self._home_dir)
134 os.environ['HOME'] = self._current_home134 os.environ['HOME'] = self._current_home
135 self._tac.tearDown()135 self._tac.tearDown()
@@ -199,7 +199,7 @@
199 super(TestPoppy, self).setUp()199 super(TestPoppy, self).setUp()
200 self.root_dir = self.makeTemporaryDirectory()200 self.root_dir = self.makeTemporaryDirectory()
201 self.server = self.server_factory(self.root_dir, self.factory)201 self.server = self.server_factory(self.root_dir, self.factory)
202 self.installFixture(self.server)202 self.useFixture(self.server)
203203
204 def _uploadPath(self, path):204 def _uploadPath(self, path):
205 """Return system path of specified path inside an upload.205 """Return system path of specified path inside an upload.
206206
=== modified file 'lib/lp/testing/__init__.py'
--- lib/lp/testing/__init__.py 2010-10-05 01:54:15 +0000
+++ lib/lp/testing/__init__.py 2010-10-17 21:28:46 +0000
@@ -325,20 +325,6 @@
325 transaction.commit()325 transaction.commit()
326 self.layer.switchDbUser(dbuser)326 self.layer.switchDbUser(dbuser)
327327
328 def installFixture(self, fixture):
329 """Install 'fixture', an object that has a `setUp` and `tearDown`.
330
331 `installFixture` will run 'fixture.setUp' and schedule
332 'fixture.tearDown' to be run during the test's tear down (using
333 `addCleanup`).
334
335 :param fixture: Any object that has a `setUp` and `tearDown` method.
336 :return: `fixture`.
337 """
338 fixture.setUp()
339 self.addCleanup(fixture.tearDown)
340 return fixture
341
342 def __str__(self):328 def __str__(self):
343 """The string representation of a test is its id.329 """The string representation of a test is its id.
344330
@@ -511,7 +497,7 @@
511 self.factory = ObjectFactory()497 self.factory = ObjectFactory()
512 # Record the oopses generated during the test run.498 # Record the oopses generated during the test run.
513 self.oopses = []499 self.oopses = []
514 self.installFixture(ZopeEventHandlerFixture(self._recordOops))500 self.useFixture(ZopeEventHandlerFixture(self._recordOops))
515 self.addCleanup(self.attachOopses)501 self.addCleanup(self.attachOopses)
516502
517 @adapter(ErrorReportEvent)503 @adapter(ErrorReportEvent)
518504
=== modified file 'lib/lp/testing/fixture.py'
--- lib/lp/testing/fixture.py 2010-08-20 20:31:18 +0000
+++ lib/lp/testing/fixture.py 2010-10-17 21:28:46 +0000
@@ -1,121 +1,25 @@
1# Copyright 2009, 2010 Canonical Ltd. This software is licensed under the1# Copyright 2009, 2010 Canonical Ltd. This software is licensed under the
2# GNU Affero General Public License version 3 (see the file LICENSE).2# GNU Affero General Public License version 3 (see the file LICENSE).
33
4# pylint: disable-msg=E02114"""Launchpad test fixtures that have no better home."""
5
6"""Basic support for 'fixtures'.
7
8In this case, 'fixture' means an object that has a setUp and a tearDown
9method.
10"""
115
12__metaclass__ = type6__metaclass__ = type
13__all__ = [7__all__ = [
14 'Fixtures',8 'ZopeEventHandlerFixture',
15 'FixtureWithCleanup',
16 'IFixture',
17 'run_with_fixture',
18 'ServerFixture',
19 'with_fixture',
20 ]9 ]
2110
22from twisted.python.util import mergeFunctionMetadata11from fixtures import Fixture
23from zope.component import (12from zope.component import (
24 getGlobalSiteManager,13 getGlobalSiteManager,
25 provideHandler,14 provideHandler,
26 )15 )
27from zope.interface import (16
28 implements,17
29 Interface,18class ZopeEventHandlerFixture(Fixture):
30 )
31
32
33class IFixture(Interface):
34 """A fixture has a setUp and a tearDown method."""
35
36 def setUp():
37 """Set up the fixture."""
38
39 def tearDown():
40 """Tear down the fixture."""
41
42
43class FixtureWithCleanup:
44 """Fixture that allows arbitrary cleanup methods to be added.
45
46 Subclass this if you'd like to define a fixture that calls 'addCleanup'.
47 This is most often useful for fixtures that provide a way for users to
48 acquire resources arbitrarily.
49
50 Cleanups are run during 'tearDown' in reverse order to the order they were
51 added. If any of the cleanups raise an error, this error will be bubbled
52 up, causing tearDown to raise an exception, and the rest of the cleanups
53 will be run in a finally block.
54 """
55
56 implements(IFixture)
57
58 def setUp(self):
59 """See `IFixture`."""
60 self._cleanups = []
61
62 def _runCleanups(self):
63 if [] == self._cleanups:
64 return
65 f, args, kwargs = self._cleanups.pop()
66 try:
67 f(*args, **kwargs)
68 finally:
69 self._runCleanups()
70
71 def tearDown(self):
72 """See `IFixture`."""
73 self._runCleanups()
74
75 def addCleanup(self, function, *args, **kwargs):
76 """Run 'function' with arguments during tear down."""
77 self._cleanups.append((function, args, kwargs))
78
79
80class Fixtures(FixtureWithCleanup):
81 """A collection of `IFixture`s."""
82
83 def __init__(self, fixtures):
84 """Construct a fixture that groups many fixtures together.
85
86 :param fixtures: A list of `IFixture` objects.
87 """
88 self._fixtures = fixtures
89
90 def setUp(self):
91 super(Fixtures, self).setUp()
92 for fixture in self._fixtures:
93 fixture.setUp()
94 self.addCleanup(fixture.tearDown)
95
96
97def with_fixture(fixture):
98 """Decorate a function to run with a given fixture."""
99 def decorator(f):
100 def decorated(*args, **kwargs):
101 return run_with_fixture(fixture, f, fixture, *args, **kwargs)
102 return mergeFunctionMetadata(f, decorated)
103 return decorator
104
105
106def run_with_fixture(fixture, f, *args, **kwargs):
107 """Run `f` within the given `fixture`."""
108 try:
109 fixture.setUp()
110 return f(*args, **kwargs)
111 finally:
112 fixture.tearDown()
113
114
115class ZopeEventHandlerFixture(FixtureWithCleanup):
116 """A fixture that provides and then unprovides a Zope event handler."""19 """A fixture that provides and then unprovides a Zope event handler."""
11720
118 def __init__(self, handler):21 def __init__(self, handler):
22 super(ZopeEventHandlerFixture, self).__init__()
119 self._handler = handler23 self._handler = handler
12024
121 def setUp(self):25 def setUp(self):
@@ -123,18 +27,3 @@
123 gsm = getGlobalSiteManager()27 gsm = getGlobalSiteManager()
124 provideHandler(self._handler)28 provideHandler(self._handler)
125 self.addCleanup(gsm.unregisterHandler, self._handler)29 self.addCleanup(gsm.unregisterHandler, self._handler)
126
127
128class ServerFixture:
129 """Adapt a bzrlib `Server` into an `IFixture`."""
130
131 implements(IFixture)
132
133 def __init__(self, server):
134 self.server = server
135
136 def setUp(self):
137 self.server.start_server()
138
139 def tearDown(self):
140 self.server.stop_server()
14130
=== removed file 'lib/lp/testing/tests/test_fixture.py'
--- lib/lp/testing/tests/test_fixture.py 2010-08-20 20:31:18 +0000
+++ lib/lp/testing/tests/test_fixture.py 1970-01-01 00:00:00 +0000
@@ -1,138 +0,0 @@
1# Copyright 2009 Canonical Ltd. This software is licensed under the
2# GNU Affero General Public License version 3 (see the file LICENSE).
3
4"""Tests for fixture support."""
5
6__metaclass__ = type
7
8import unittest
9
10from zope.interface import implements
11
12from lp.testing import TestCase
13from lp.testing.fixture import (
14 Fixtures,
15 FixtureWithCleanup,
16 IFixture,
17 run_with_fixture,
18 with_fixture,
19 )
20
21
22class LoggingFixture:
23
24 implements(IFixture)
25
26 def __init__(self, log):
27 self.log = log
28
29 def setUp(self):
30 self.log.append('setUp')
31
32 def tearDown(self):
33 self.log.append('tearDown')
34
35
36class TestFixture(TestCase):
37
38 def test_run_with_fixture(self):
39 # run_with_fixture runs the setUp method of the fixture, the passed
40 # function and then the tearDown method of the fixture.
41 log = []
42 fixture = LoggingFixture(log)
43 run_with_fixture(fixture, log.append, 'hello')
44 self.assertEqual(['setUp', 'hello', 'tearDown'], log)
45
46 def test_run_tearDown_even_with_exception(self):
47 # run_with_fixture runs the setUp method of the fixture, the passed
48 # function and then the tearDown method of the fixture even if the
49 # function raises an exception.
50 log = []
51 fixture = LoggingFixture(log)
52 self.assertRaises(
53 ZeroDivisionError, run_with_fixture, fixture, lambda: 1/0)
54 self.assertEqual(['setUp', 'tearDown'], log)
55
56 def test_with_fixture(self):
57 # with_fixture decorates a function so that it gets passed the fixture
58 # and the fixture is set up and torn down around the function.
59 log = []
60 fixture = LoggingFixture(log)
61 @with_fixture(fixture)
62 def function(fixture, **kwargs):
63 log.append(fixture)
64 log.append(kwargs)
65 return 'oi'
66 result = function(foo='bar')
67 self.assertEqual('oi', result)
68 self.assertEqual(['setUp', fixture, {'foo': 'bar'}, 'tearDown'], log)
69
70
71class TestFixtureWithCleanup(TestCase):
72 """Tests for `FixtureWithCleanup`."""
73
74 def test_cleanup_called_during_teardown(self):
75 log = []
76 fixture = FixtureWithCleanup()
77 fixture.setUp()
78 fixture.addCleanup(log.append, 'foo')
79 self.assertEqual([], log)
80 fixture.tearDown()
81 self.assertEqual(['foo'], log)
82
83 def test_cleanup_called_in_reverse_order(self):
84 log = []
85 fixture = FixtureWithCleanup()
86 fixture.setUp()
87 fixture.addCleanup(log.append, 'foo')
88 fixture.addCleanup(log.append, 'bar')
89 fixture.tearDown()
90 self.assertEqual(['bar', 'foo'], log)
91
92 def test_cleanup_run_even_in_failure(self):
93 log = []
94 fixture = FixtureWithCleanup()
95 fixture.setUp()
96 fixture.addCleanup(log.append, 'foo')
97 fixture.addCleanup(lambda: 1/0)
98 self.assertRaises(ZeroDivisionError, fixture.tearDown)
99 self.assertEqual(['foo'], log)
100
101
102class TestFixtures(TestCase):
103 """Tests the `Fixtures` class, which groups multiple `IFixture`s."""
104
105 class LoggingFixture:
106
107 def __init__(self, log):
108 self._log = log
109
110 def setUp(self):
111 self._log.append((self, 'setUp'))
112
113 def tearDown(self):
114 self._log.append((self, 'tearDown'))
115
116 def test_with_single_fixture(self):
117 log = []
118 a = self.LoggingFixture(log)
119 fixtures = Fixtures([a])
120 fixtures.setUp()
121 fixtures.tearDown()
122 self.assertEqual([(a, 'setUp'), (a, 'tearDown')], log)
123
124 def test_with_multiple_fixtures(self):
125 log = []
126 a = self.LoggingFixture(log)
127 b = self.LoggingFixture(log)
128 fixtures = Fixtures([a, b])
129 fixtures.setUp()
130 fixtures.tearDown()
131 self.assertEqual(
132 [(a, 'setUp'), (b, 'setUp'), (b, 'tearDown'), (a, 'tearDown')],
133 log)
134
135
136def test_suite():
137 return unittest.TestLoader().loadTestsFromName(__name__)
138