1#  testresources: extensions to python unittest to allow declaritive use
2#  of resources by test cases.
3#
4#  Copyright (c) 2005-2010 Testresources Contributors
5#
6#  Licensed under either the Apache License, Version 2.0 or the BSD 3-clause
7#  license at the users choice. A copy of both licenses are available in the
8#  project source as Apache-2.0 and BSD. You may not use this file except in
9#  compliance with one of these two licences.
10#
11#  Unless required by applicable law or agreed to in writing, software distributed
12#  under these licenses is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
13#  CONDITIONS OF ANY KIND, either express or implied.  See the license you chose
14#  for the specific language governing permissions and limitations under that
15#  license.
16#
17
18from fixtures.tests.helpers import LoggingFixture
19import testtools
20
21import testresources
22from testresources.tests import (
23    ResultWithResourceExtensions,
24    ResultWithoutResourceExtensions,
25    )
26
27
28def test_suite():
29    loader = testresources.tests.TestUtil.TestLoader()
30    result = loader.loadTestsFromName(__name__)
31    return result
32
33
34class MockResourceInstance(object):
35
36    def __init__(self, name):
37        self._name = name
38
39    def __eq__(self, other):
40        return self.__dict__ == other.__dict__
41
42    def __cmp__(self, other):
43        return cmp(self.__dict__, other.__dict__)
44
45    def __repr__(self):
46        return self._name
47
48
49class MockResource(testresources.TestResourceManager):
50    """Mock resource that logs the number of make and clean calls."""
51
52    def __init__(self):
53        super(MockResource, self).__init__()
54        self.makes = 0
55        self.cleans = 0
56
57    def clean(self, resource):
58        self.cleans += 1
59
60    def make(self, dependency_resources):
61        self.makes += 1
62        return MockResourceInstance("Boo!")
63
64
65class MockResettableResource(MockResource):
66    """Mock resource that logs the number of reset calls too."""
67
68    def __init__(self):
69        super(MockResettableResource, self).__init__()
70        self.resets = 0
71
72    def _reset(self, resource, dependency_resources):
73        self.resets += 1
74        resource._name += "!"
75        self._dirty = False
76        return resource
77
78
79class TestTestResource(testtools.TestCase):
80
81    def testUnimplementedGetResource(self):
82        # By default, TestResource raises NotImplementedError on getResource
83        # because make is not defined initially.
84        resource_manager = testresources.TestResource()
85        self.assertRaises(NotImplementedError, resource_manager.getResource)
86
87    def testInitiallyNotDirty(self):
88        resource_manager = testresources.TestResource()
89        self.assertEqual(False, resource_manager._dirty)
90
91    def testInitiallyUnused(self):
92        resource_manager = testresources.TestResource()
93        self.assertEqual(0, resource_manager._uses)
94
95    def testInitiallyNoCurrentResource(self):
96        resource_manager = testresources.TestResource()
97        self.assertEqual(None, resource_manager._currentResource)
98
99    def testneededResourcesDefault(self):
100        # Calling neededResources on a default TestResource returns the
101        # resource.
102        resource = testresources.TestResource()
103        self.assertEqual([resource], resource.neededResources())
104
105    def testneededResourcesDependenciesFirst(self):
106        # Calling neededResources on a TestResource with dependencies puts the
107        # dependencies first.
108        resource = testresources.TestResource()
109        dep1 = testresources.TestResource()
110        dep2 = testresources.TestResource()
111        resource.resources.append(("dep1", dep1))
112        resource.resources.append(("dep2", dep2))
113        self.assertEqual([dep1, dep2, resource], resource.neededResources())
114
115    def testneededResourcesClosure(self):
116        # Calling neededResources on a TestResource with dependencies includes
117        # the needed resources of the needed resources.
118        resource = testresources.TestResource()
119        dep1 = testresources.TestResource()
120        dep2 = testresources.TestResource()
121        resource.resources.append(("dep1", dep1))
122        dep1.resources.append(("dep2", dep2))
123        self.assertEqual([dep2, dep1, resource], resource.neededResources())
124
125    def testDefaultCosts(self):
126        # The base TestResource costs 1 to set up and to tear down.
127        resource_manager = testresources.TestResource()
128        self.assertEqual(resource_manager.setUpCost, 1)
129        self.assertEqual(resource_manager.tearDownCost, 1)
130
131    def testGetResourceReturnsMakeResource(self):
132        resource_manager = MockResource()
133        resource = resource_manager.getResource()
134        self.assertEqual(resource_manager.make({}), resource)
135
136    def testGetResourceIncrementsUses(self):
137        resource_manager = MockResource()
138        resource_manager.getResource()
139        self.assertEqual(1, resource_manager._uses)
140        resource_manager.getResource()
141        self.assertEqual(2, resource_manager._uses)
142
143    def testGetResourceDoesntDirty(self):
144        resource_manager = MockResource()
145        resource_manager.getResource()
146        self.assertEqual(resource_manager._dirty, False)
147
148    def testGetResourceSetsCurrentResource(self):
149        resource_manager = MockResource()
150        resource = resource_manager.getResource()
151        self.assertIs(resource_manager._currentResource, resource)
152
153    def testGetResourceTwiceReturnsIdenticalResource(self):
154        resource_manager = MockResource()
155        resource1 = resource_manager.getResource()
156        resource2 = resource_manager.getResource()
157        self.assertIs(resource1, resource2)
158
159    def testGetResourceCallsMakeResource(self):
160        resource_manager = MockResource()
161        resource_manager.getResource()
162        self.assertEqual(1, resource_manager.makes)
163
164    def testIsDirty(self):
165        resource_manager = MockResource()
166        r = resource_manager.getResource()
167        resource_manager.dirtied(r)
168        self.assertTrue(resource_manager.isDirty())
169        resource_manager.finishedWith(r)
170
171    def testIsDirtyIsTrueIfDependenciesChanged(self):
172        resource_manager = MockResource()
173        dep1 = MockResource()
174        dep2 = MockResource()
175        dep3 = MockResource()
176        resource_manager.resources.append(("dep1", dep1))
177        resource_manager.resources.append(("dep2", dep2))
178        resource_manager.resources.append(("dep3", dep3))
179        r = resource_manager.getResource()
180        dep2.dirtied(r.dep2)
181        r2 =dep2.getResource()
182        self.assertTrue(resource_manager.isDirty())
183        resource_manager.finishedWith(r)
184        dep2.finishedWith(r2)
185
186    def testIsDirtyIsTrueIfDependenciesAreDirty(self):
187        resource_manager = MockResource()
188        dep1 = MockResource()
189        dep2 = MockResource()
190        dep3 = MockResource()
191        resource_manager.resources.append(("dep1", dep1))
192        resource_manager.resources.append(("dep2", dep2))
193        resource_manager.resources.append(("dep3", dep3))
194        r = resource_manager.getResource()
195        dep2.dirtied(r.dep2)
196        self.assertTrue(resource_manager.isDirty())
197        resource_manager.finishedWith(r)
198
199    def testRepeatedGetResourceCallsMakeResourceOnceOnly(self):
200        resource_manager = MockResource()
201        resource_manager.getResource()
202        resource_manager.getResource()
203        self.assertEqual(1, resource_manager.makes)
204
205    def testGetResourceResetsUsedResource(self):
206        resource_manager = MockResettableResource()
207        resource_manager.getResource()
208        resource = resource_manager.getResource()
209        self.assertEqual(1, resource_manager.makes)
210        resource_manager.dirtied(resource)
211        resource_manager.getResource()
212        self.assertEqual(1, resource_manager.makes)
213        self.assertEqual(1, resource_manager.resets)
214        resource_manager.finishedWith(resource)
215
216    def testIsResetIfDependenciesAreDirty(self):
217        resource_manager = MockResource()
218        dep1 = MockResettableResource()
219        resource_manager.resources.append(("dep1", dep1))
220        r = resource_manager.getResource()
221        dep1.dirtied(r.dep1)
222        # if we get the resource again, it should be cleaned.
223        r = resource_manager.getResource()
224        self.assertFalse(resource_manager.isDirty())
225        self.assertFalse(dep1.isDirty())
226        resource_manager.finishedWith(r)
227        resource_manager.finishedWith(r)
228
229    def testUsedResourceResetBetweenUses(self):
230        resource_manager = MockResettableResource()
231        # take two refs; like happens with OptimisingTestSuite.
232        resource_manager.getResource()
233        resource = resource_manager.getResource()
234        resource_manager.dirtied(resource)
235        resource_manager.finishedWith(resource)
236        # Get again, but its been dirtied.
237        resource = resource_manager.getResource()
238        resource_manager.finishedWith(resource)
239        resource_manager.finishedWith(resource)
240        # The resource is made once, reset once and cleaned once.
241        self.assertEqual(1, resource_manager.makes)
242        self.assertEqual(1, resource_manager.resets)
243        self.assertEqual(1, resource_manager.cleans)
244
245    def testFinishedWithDecrementsUses(self):
246        resource_manager = MockResource()
247        resource = resource_manager.getResource()
248        resource = resource_manager.getResource()
249        self.assertEqual(2, resource_manager._uses)
250        resource_manager.finishedWith(resource)
251        self.assertEqual(1, resource_manager._uses)
252        resource_manager.finishedWith(resource)
253        self.assertEqual(0, resource_manager._uses)
254
255    def testFinishedWithResetsCurrentResource(self):
256        resource_manager = MockResource()
257        resource = resource_manager.getResource()
258        resource_manager.finishedWith(resource)
259        self.assertIs(None, resource_manager._currentResource)
260
261    def testFinishedWithCallsCleanResource(self):
262        resource_manager = MockResource()
263        resource = resource_manager.getResource()
264        resource_manager.finishedWith(resource)
265        self.assertEqual(1, resource_manager.cleans)
266
267    def testUsingTwiceMakesAndCleansTwice(self):
268        resource_manager = MockResource()
269        resource = resource_manager.getResource()
270        resource_manager.finishedWith(resource)
271        resource = resource_manager.getResource()
272        resource_manager.finishedWith(resource)
273        self.assertEqual(2, resource_manager.makes)
274        self.assertEqual(2, resource_manager.cleans)
275
276    def testFinishedWithCallsCleanResourceOnceOnly(self):
277        resource_manager = MockResource()
278        resource = resource_manager.getResource()
279        resource = resource_manager.getResource()
280        resource_manager.finishedWith(resource)
281        self.assertEqual(0, resource_manager.cleans)
282        resource_manager.finishedWith(resource)
283        self.assertEqual(1, resource_manager.cleans)
284
285    def testFinishedWithMarksNonDirty(self):
286        resource_manager = MockResource()
287        resource = resource_manager.getResource()
288        resource_manager.dirtied(resource)
289        resource_manager.finishedWith(resource)
290        self.assertEqual(False, resource_manager._dirty)
291
292    def testResourceAvailableBetweenFinishedWithCalls(self):
293        resource_manager = MockResource()
294        resource = resource_manager.getResource()
295        resource = resource_manager.getResource()
296        resource_manager.finishedWith(resource)
297        self.assertIs(resource, resource_manager._currentResource)
298        resource_manager.finishedWith(resource)
299
300    def testDirtiedSetsDirty(self):
301        resource_manager = MockResource()
302        resource = resource_manager.getResource()
303        self.assertEqual(False, resource_manager._dirty)
304        resource_manager.dirtied(resource)
305        self.assertEqual(True, resource_manager._dirty)
306
307    def testDirtyingResourceTriggersCleanOnGet(self):
308        resource_manager = MockResource()
309        resource1 = resource_manager.getResource()
310        resource2 = resource_manager.getResource()
311        resource_manager.dirtied(resource2)
312        resource_manager.finishedWith(resource2)
313        self.assertEqual(0, resource_manager.cleans)
314        resource3 = resource_manager.getResource()
315        self.assertEqual(1, resource_manager.cleans)
316        resource_manager.finishedWith(resource3)
317        resource_manager.finishedWith(resource1)
318        self.assertEqual(2, resource_manager.cleans)
319
320    def testDefaultResetMethodPreservesCleanResource(self):
321        resource_manager = MockResource()
322        resource = resource_manager.getResource()
323        self.assertEqual(1, resource_manager.makes)
324        self.assertEqual(False, resource_manager._dirty)
325        resource_manager.reset(resource)
326        self.assertEqual(1, resource_manager.makes)
327        self.assertEqual(0, resource_manager.cleans)
328
329    def testDefaultResetMethodRecreatesDirtyResource(self):
330        resource_manager = MockResource()
331        resource = resource_manager.getResource()
332        self.assertEqual(1, resource_manager.makes)
333        resource_manager.dirtied(resource)
334        resource_manager.reset(resource)
335        self.assertEqual(2, resource_manager.makes)
336        self.assertEqual(1, resource_manager.cleans)
337
338    def testDefaultResetResetsDependencies(self):
339        resource_manager = MockResettableResource()
340        dep1 = MockResettableResource()
341        dep2 = MockResettableResource()
342        resource_manager.resources.append(("dep1", dep1))
343        resource_manager.resources.append(("dep2", dep2))
344        # A typical OptimisingTestSuite workflow
345        r_outer = resource_manager.getResource()
346        # test 1
347        r_inner = resource_manager.getResource()
348        dep2.dirtied(r_inner.dep2)
349        resource_manager.finishedWith(r_inner)
350        # test 2
351        r_inner = resource_manager.getResource()
352        dep2.dirtied(r_inner.dep2)
353        resource_manager.finishedWith(r_inner)
354        resource_manager.finishedWith(r_outer)
355        # Dep 1 was clean, doesn't do a reset, and should only have one
356        # make+clean.
357        self.assertEqual(1, dep1.makes)
358        self.assertEqual(1, dep1.cleans)
359        self.assertEqual(0, dep1.resets)
360        # Dep 2 was dirty, so _reset happens, and likewise only one make and
361        # clean.
362        self.assertEqual(1, dep2.makes)
363        self.assertEqual(1, dep2.cleans)
364        self.assertEqual(1, dep2.resets)
365        # The top layer should have had a reset happen, and only one make and
366        # clean.
367        self.assertEqual(1, resource_manager.makes)
368        self.assertEqual(1, resource_manager.cleans)
369        self.assertEqual(1, resource_manager.resets)
370
371    def testDirtyingWhenUnused(self):
372        resource_manager = MockResource()
373        resource = resource_manager.getResource()
374        resource_manager.finishedWith(resource)
375        resource_manager.dirtied(resource)
376        self.assertEqual(1, resource_manager.makes)
377        resource = resource_manager.getResource()
378        self.assertEqual(2, resource_manager.makes)
379
380    def testFinishedActivityForResourceWithoutExtensions(self):
381        result = ResultWithoutResourceExtensions()
382        resource_manager = MockResource()
383        r = resource_manager.getResource()
384        resource_manager.finishedWith(r, result)
385
386    def testFinishedActivityForResourceWithExtensions(self):
387        result = ResultWithResourceExtensions()
388        resource_manager = MockResource()
389        r = resource_manager.getResource()
390        expected = [("clean", "start", resource_manager),
391            ("clean", "stop", resource_manager)]
392        resource_manager.finishedWith(r, result)
393        self.assertEqual(expected, result._calls)
394
395    def testGetActivityForResourceWithoutExtensions(self):
396        result = ResultWithoutResourceExtensions()
397        resource_manager = MockResource()
398        r = resource_manager.getResource(result)
399        resource_manager.finishedWith(r)
400
401    def testGetActivityForResourceWithExtensions(self):
402        result = ResultWithResourceExtensions()
403        resource_manager = MockResource()
404        r = resource_manager.getResource(result)
405        expected = [("make", "start", resource_manager),
406            ("make", "stop", resource_manager)]
407        resource_manager.finishedWith(r)
408        self.assertEqual(expected, result._calls)
409
410    def testResetActivityForResourceWithoutExtensions(self):
411        result = ResultWithoutResourceExtensions()
412        resource_manager = MockResource()
413        resource_manager.getResource()
414        r = resource_manager.getResource()
415        resource_manager.dirtied(r)
416        resource_manager.finishedWith(r)
417        r = resource_manager.getResource(result)
418        resource_manager.dirtied(r)
419        resource_manager.finishedWith(r)
420        resource_manager.finishedWith(resource_manager._currentResource)
421
422    def testResetActivityForResourceWithExtensions(self):
423        result = ResultWithResourceExtensions()
424        resource_manager = MockResource()
425        expected = [("reset", "start", resource_manager),
426            ("reset", "stop", resource_manager),
427            ]
428        resource_manager.getResource()
429        r = resource_manager.getResource()
430        resource_manager.dirtied(r)
431        resource_manager.finishedWith(r)
432        r = resource_manager.getResource(result)
433        resource_manager.dirtied(r)
434        resource_manager.finishedWith(r)
435        resource_manager.finishedWith(resource_manager._currentResource)
436        self.assertEqual(expected, result._calls)
437
438
439class TestGenericResource(testtools.TestCase):
440
441    def test_default_uses_setUp_tearDown(self):
442        calls = []
443        class Wrapped:
444            def setUp(self):
445                calls.append('setUp')
446            def tearDown(self):
447                calls.append('tearDown')
448        mgr = testresources.GenericResource(Wrapped)
449        resource = mgr.getResource()
450        self.assertEqual(['setUp'], calls)
451        mgr.finishedWith(resource)
452        self.assertEqual(['setUp', 'tearDown'], calls)
453        self.assertIsInstance(resource, Wrapped)
454
455    def test_dependencies_passed_to_factory(self):
456        calls = []
457        class Wrapped:
458            def __init__(self, **args):
459                calls.append(args)
460            def setUp(self):pass
461            def tearDown(self):pass
462        class Trivial(testresources.TestResource):
463            def __init__(self, thing):
464                testresources.TestResource.__init__(self)
465                self.thing = thing
466            def make(self, dependency_resources):return self.thing
467            def clean(self, resource):pass
468        mgr = testresources.GenericResource(Wrapped)
469        mgr.resources = [('foo', Trivial('foo')), ('bar', Trivial('bar'))]
470        resource = mgr.getResource()
471        self.assertEqual([{'foo':'foo', 'bar':'bar'}], calls)
472        mgr.finishedWith(resource)
473
474    def test_setup_teardown_controllable(self):
475        calls = []
476        class Wrapped:
477            def start(self):
478                calls.append('setUp')
479            def stop(self):
480                calls.append('tearDown')
481        mgr = testresources.GenericResource(Wrapped,
482            setup_method_name='start', teardown_method_name='stop')
483        resource = mgr.getResource()
484        self.assertEqual(['setUp'], calls)
485        mgr.finishedWith(resource)
486        self.assertEqual(['setUp', 'tearDown'], calls)
487        self.assertIsInstance(resource, Wrapped)
488
489    def test_always_dirty(self):
490        class Wrapped:
491            def setUp(self):pass
492            def tearDown(self):pass
493        mgr = testresources.GenericResource(Wrapped)
494        resource = mgr.getResource()
495        self.assertTrue(mgr.isDirty())
496        mgr.finishedWith(resource)
497
498
499class TestFixtureResource(testtools.TestCase):
500
501    def test_uses_setUp_cleanUp(self):
502        fixture = LoggingFixture()
503        mgr = testresources.FixtureResource(fixture)
504        resource = mgr.getResource()
505        self.assertEqual(fixture, resource)
506        self.assertEqual(['setUp'], fixture.calls)
507        mgr.finishedWith(resource)
508        self.assertEqual(['setUp', 'cleanUp'], fixture.calls)
509
510    def test_always_dirty(self):
511        fixture = LoggingFixture()
512        mgr = testresources.FixtureResource(fixture)
513        resource = mgr.getResource()
514        self.assertTrue(mgr.isDirty())
515        mgr.finishedWith(resource)
516
517    def test_reset_called(self):
518        fixture = LoggingFixture()
519        mgr = testresources.FixtureResource(fixture)
520        resource = mgr.getResource()
521        mgr.reset(resource)
522        mgr.finishedWith(resource)
523        self.assertEqual(
524            ['setUp', 'reset', 'cleanUp'], fixture.calls)
525