835
834
self.assertContainsRe(output,
836
835
r"LSProf output for <type 'unicode'>\(\('world',\), {'errors': 'replace'}\)\n")
837
def test_uses_time_from_testtools(self):
838
"""Test case timings in verbose results should use testtools times"""
840
class TimeAddedVerboseTestResult(tests.VerboseTestResult):
841
def startTest(self, test):
842
self.time(datetime.datetime.utcfromtimestamp(1.145))
843
super(TimeAddedVerboseTestResult, self).startTest(test)
844
def addSuccess(self, test):
845
self.time(datetime.datetime.utcfromtimestamp(51.147))
846
super(TimeAddedVerboseTestResult, self).addSuccess(test)
847
def report_tests_starting(self): pass
849
self.get_passing_test().run(TimeAddedVerboseTestResult(sio, 0, 2))
850
self.assertEndsWith(sio.getvalue(), "OK 50002ms\n")
838
852
def test_known_failure(self):
839
853
"""A KnownFailure being raised should trigger several result actions."""
840
854
class InstrumentedTestResult(tests.ExtendedTestResult):
841
855
def stopTestRun(self): pass
842
def startTests(self): pass
843
def report_test_start(self, test): pass
856
def report_tests_starting(self): pass
844
857
def report_known_failure(self, test, err=None, details=None):
845
858
self._call = test, 'known failure'
846
859
result = InstrumentedTestResult(None, None, None, None)
1213
1236
self.assertContainsRe(output_string, "--date [0-9.]+")
1214
1237
self.assertLength(1, self._get_source_tree_calls)
1239
def test_verbose_test_count(self):
1240
"""A verbose test run reports the right test count at the start"""
1241
suite = TestUtil.TestSuite([
1242
unittest.FunctionTestCase(lambda:None),
1243
unittest.FunctionTestCase(lambda:None)])
1244
self.assertEqual(suite.countTestCases(), 2)
1246
runner = tests.TextTestRunner(stream=stream, verbosity=2)
1247
# Need to use the CountingDecorator as that's what sets num_tests
1248
result = self.run_test_runner(runner, tests.CountingDecorator(suite))
1249
self.assertStartsWith(stream.getvalue(), "running 2 tests")
1216
1251
def test_startTestRun(self):
1217
1252
"""run should call result.startTestRun()"""
1219
class LoggingDecorator(tests.ForwardingResult):
1254
class LoggingDecorator(ExtendedToOriginalDecorator):
1220
1255
def startTestRun(self):
1221
tests.ForwardingResult.startTestRun(self)
1256
ExtendedToOriginalDecorator.startTestRun(self)
1222
1257
calls.append('startTestRun')
1223
1258
test = unittest.FunctionTestCase(lambda:None)
1224
1259
stream = StringIO()
1655
1707
self.assertEqual('original', obj.test_attr)
1710
class _MissingFeature(tests.Feature):
1713
missing_feature = _MissingFeature()
1716
def _get_test(name):
1717
"""Get an instance of a specific example test.
1719
We protect this in a function so that they don't auto-run in the test
1723
class ExampleTests(tests.TestCase):
1725
def test_fail(self):
1726
mutter('this was a failing test')
1727
self.fail('this test will fail')
1729
def test_error(self):
1730
mutter('this test errored')
1731
raise RuntimeError('gotcha')
1733
def test_missing_feature(self):
1734
mutter('missing the feature')
1735
self.requireFeature(missing_feature)
1737
def test_skip(self):
1738
mutter('this test will be skipped')
1739
raise tests.TestSkipped('reason')
1741
def test_success(self):
1742
mutter('this test succeeds')
1744
def test_xfail(self):
1745
mutter('test with expected failure')
1746
self.knownFailure('this_fails')
1748
def test_unexpected_success(self):
1749
mutter('test with unexpected success')
1750
self.expectFailure('should_fail', lambda: None)
1752
return ExampleTests(name)
1755
class TestTestCaseLogDetails(tests.TestCase):
1757
def _run_test(self, test_name):
1758
test = _get_test(test_name)
1759
result = testtools.TestResult()
1763
def test_fail_has_log(self):
1764
result = self._run_test('test_fail')
1765
self.assertEqual(1, len(result.failures))
1766
result_content = result.failures[0][1]
1767
self.assertContainsRe(result_content, 'Text attachment: log')
1768
self.assertContainsRe(result_content, 'this was a failing test')
1770
def test_error_has_log(self):
1771
result = self._run_test('test_error')
1772
self.assertEqual(1, len(result.errors))
1773
result_content = result.errors[0][1]
1774
self.assertContainsRe(result_content, 'Text attachment: log')
1775
self.assertContainsRe(result_content, 'this test errored')
1777
def test_skip_has_no_log(self):
1778
result = self._run_test('test_skip')
1779
self.assertEqual(['reason'], result.skip_reasons.keys())
1780
skips = result.skip_reasons['reason']
1781
self.assertEqual(1, len(skips))
1783
self.assertFalse('log' in test.getDetails())
1785
def test_missing_feature_has_no_log(self):
1786
# testtools doesn't know about addNotSupported, so it just gets
1787
# considered as a skip
1788
result = self._run_test('test_missing_feature')
1789
self.assertEqual([missing_feature], result.skip_reasons.keys())
1790
skips = result.skip_reasons[missing_feature]
1791
self.assertEqual(1, len(skips))
1793
self.assertFalse('log' in test.getDetails())
1795
def test_xfail_has_no_log(self):
1796
result = self._run_test('test_xfail')
1797
self.assertEqual(1, len(result.expectedFailures))
1798
result_content = result.expectedFailures[0][1]
1799
self.assertNotContainsRe(result_content, 'Text attachment: log')
1800
self.assertNotContainsRe(result_content, 'test with expected failure')
1802
def test_unexpected_success_has_log(self):
1803
result = self._run_test('test_unexpected_success')
1804
self.assertEqual(1, len(result.unexpectedSuccesses))
1805
# Inconsistency, unexpectedSuccesses is a list of tests,
1806
# expectedFailures is a list of reasons?
1807
test = result.unexpectedSuccesses[0]
1808
details = test.getDetails()
1809
self.assertTrue('log' in details)
1812
class TestTestCloning(tests.TestCase):
1813
"""Tests that test cloning of TestCases (as used by multiply_tests)."""
1815
def test_cloned_testcase_does_not_share_details(self):
1816
"""A TestCase cloned with clone_test does not share mutable attributes
1817
such as details or cleanups.
1819
class Test(tests.TestCase):
1821
self.addDetail('foo', Content('text/plain', lambda: 'foo'))
1822
orig_test = Test('test_foo')
1823
cloned_test = tests.clone_test(orig_test, orig_test.id() + '(cloned)')
1824
orig_test.run(unittest.TestResult())
1825
self.assertEqual('foo', orig_test.getDetails()['foo'].iter_bytes())
1826
self.assertEqual(None, cloned_test.getDetails().get('foo'))
1828
def test_double_apply_scenario_preserves_first_scenario(self):
1829
"""Applying two levels of scenarios to a test preserves the attributes
1830
added by both scenarios.
1832
class Test(tests.TestCase):
1835
test = Test('test_foo')
1836
scenarios_x = [('x=1', {'x': 1}), ('x=2', {'x': 2})]
1837
scenarios_y = [('y=1', {'y': 1}), ('y=2', {'y': 2})]
1838
suite = tests.multiply_tests(test, scenarios_x, unittest.TestSuite())
1839
suite = tests.multiply_tests(suite, scenarios_y, unittest.TestSuite())
1840
all_tests = list(tests.iter_suite_tests(suite))
1841
self.assertLength(4, all_tests)
1842
all_xys = sorted((t.x, t.y) for t in all_tests)
1843
self.assertEqual([(1, 1), (1, 2), (2, 1), (2, 2)], all_xys)
1658
1846
# NB: Don't delete this; it's not actually from 0.11!
1659
1847
@deprecated_function(deprecated_in((0, 11, 0)))
1660
1848
def sample_deprecated_function():
1971
2156
load_list='missing file name', list_only=True)
2159
class TestSubunitLogDetails(tests.TestCase, SelfTestHelper):
2161
_test_needs_features = [features.subunit]
2163
def run_subunit_stream(self, test_name):
2164
from subunit import ProtocolTestCase
2166
return TestUtil.TestSuite([_get_test(test_name)])
2167
stream = self.run_selftest(runner_class=tests.SubUnitBzrRunner,
2168
test_suite_factory=factory)
2169
test = ProtocolTestCase(stream)
2170
result = testtools.TestResult()
2172
content = stream.getvalue()
2173
return content, result
2175
def test_fail_has_log(self):
2176
content, result = self.run_subunit_stream('test_fail')
2177
self.assertEqual(1, len(result.failures))
2178
self.assertContainsRe(content, '(?m)^log$')
2179
self.assertContainsRe(content, 'this test will fail')
2181
def test_error_has_log(self):
2182
content, result = self.run_subunit_stream('test_error')
2183
self.assertContainsRe(content, '(?m)^log$')
2184
self.assertContainsRe(content, 'this test errored')
2186
def test_skip_has_no_log(self):
2187
content, result = self.run_subunit_stream('test_skip')
2188
self.assertNotContainsRe(content, '(?m)^log$')
2189
self.assertNotContainsRe(content, 'this test will be skipped')
2190
self.assertEqual(['reason'], result.skip_reasons.keys())
2191
skips = result.skip_reasons['reason']
2192
self.assertEqual(1, len(skips))
2194
# RemotedTestCase doesn't preserve the "details"
2195
## self.assertFalse('log' in test.getDetails())
2197
def test_missing_feature_has_no_log(self):
2198
content, result = self.run_subunit_stream('test_missing_feature')
2199
self.assertNotContainsRe(content, '(?m)^log$')
2200
self.assertNotContainsRe(content, 'missing the feature')
2201
self.assertEqual(['_MissingFeature\n'], result.skip_reasons.keys())
2202
skips = result.skip_reasons['_MissingFeature\n']
2203
self.assertEqual(1, len(skips))
2205
# RemotedTestCase doesn't preserve the "details"
2206
## self.assertFalse('log' in test.getDetails())
2208
def test_xfail_has_no_log(self):
2209
content, result = self.run_subunit_stream('test_xfail')
2210
self.assertNotContainsRe(content, '(?m)^log$')
2211
self.assertNotContainsRe(content, 'test with expected failure')
2212
self.assertEqual(1, len(result.expectedFailures))
2213
result_content = result.expectedFailures[0][1]
2214
self.assertNotContainsRe(result_content, 'Text attachment: log')
2215
self.assertNotContainsRe(result_content, 'test with expected failure')
2217
def test_unexpected_success_has_log(self):
2218
content, result = self.run_subunit_stream('test_unexpected_success')
2219
self.assertContainsRe(content, '(?m)^log$')
2220
self.assertContainsRe(content, 'test with unexpected success')
2221
self.expectFailure('subunit treats "unexpectedSuccess"'
2222
' as a plain success',
2223
self.assertEqual, 1, len(result.unexpectedSuccesses))
2224
self.assertEqual(1, len(result.unexpectedSuccesses))
2225
test = result.unexpectedSuccesses[0]
2226
# RemotedTestCase doesn't preserve the "details"
2227
## self.assertTrue('log' in test.getDetails())
2229
def test_success_has_no_log(self):
2230
content, result = self.run_subunit_stream('test_success')
2231
self.assertEqual(1, result.testsRun)
2232
self.assertNotContainsRe(content, '(?m)^log$')
2233
self.assertNotContainsRe(content, 'this test succeeds')
1974
2236
class TestRunBzr(tests.TestCase):
2960
3228
self.assertEquals('bzrlib.plugins', tpr.resolve_alias('bp'))
3231
class TestThreadLeakDetection(tests.TestCase):
3232
"""Ensure when tests leak threads we detect and report it"""
3234
class LeakRecordingResult(tests.ExtendedTestResult):
3236
tests.ExtendedTestResult.__init__(self, StringIO(), 0, 1)
3238
def _report_thread_leak(self, test, leaks, alive):
3239
self.leaks.append((test, leaks))
3241
def test_testcase_without_addCleanups(self):
3242
"""Check old TestCase instances don't break with leak detection"""
3243
class Test(unittest.TestCase):
3246
result = self.LeakRecordingResult()
3248
result.startTestRun()
3250
result.stopTestRun()
3251
self.assertEqual(result._tests_leaking_threads_count, 0)
3252
self.assertEqual(result.leaks, [])
3254
def test_thread_leak(self):
3255
"""Ensure a thread that outlives the running of a test is reported
3257
Uses a thread that blocks on an event, and is started by the inner
3258
test case. As the thread outlives the inner case's run, it should be
3259
detected as a leak, but the event is then set so that the thread can
3260
be safely joined in cleanup so it's not leaked for real.
3262
event = threading.Event()
3263
thread = threading.Thread(name="Leaker", target=event.wait)
3264
class Test(tests.TestCase):
3265
def test_leak(self):
3267
result = self.LeakRecordingResult()
3268
test = Test("test_leak")
3269
self.addCleanup(thread.join)
3270
self.addCleanup(event.set)
3271
result.startTestRun()
3273
result.stopTestRun()
3274
self.assertEqual(result._tests_leaking_threads_count, 1)
3275
self.assertEqual(result._first_thread_leaker_id, test.id())
3276
self.assertEqual(result.leaks, [(test, set([thread]))])
3277
self.assertContainsString(result.stream.getvalue(), "leaking threads")
3279
def test_multiple_leaks(self):
3280
"""Check multiple leaks are blamed on the test cases at fault
3282
Same concept as the previous test, but has one inner test method that
3283
leaks two threads, and one that doesn't leak at all.
3285
event = threading.Event()
3286
thread_a = threading.Thread(name="LeakerA", target=event.wait)
3287
thread_b = threading.Thread(name="LeakerB", target=event.wait)
3288
thread_c = threading.Thread(name="LeakerC", target=event.wait)
3289
class Test(tests.TestCase):
3290
def test_first_leak(self):
3292
def test_second_no_leak(self):
3294
def test_third_leak(self):
3297
result = self.LeakRecordingResult()
3298
first_test = Test("test_first_leak")
3299
third_test = Test("test_third_leak")
3300
self.addCleanup(thread_a.join)
3301
self.addCleanup(thread_b.join)
3302
self.addCleanup(thread_c.join)
3303
self.addCleanup(event.set)
3304
result.startTestRun()
3306
[first_test, Test("test_second_no_leak"), third_test]
3308
result.stopTestRun()
3309
self.assertEqual(result._tests_leaking_threads_count, 2)
3310
self.assertEqual(result._first_thread_leaker_id, first_test.id())
3311
self.assertEqual(result.leaks, [
3312
(first_test, set([thread_b])),
3313
(third_test, set([thread_a, thread_c]))])
3314
self.assertContainsString(result.stream.getvalue(), "leaking threads")
3317
class TestPostMortemDebugging(tests.TestCase):
3318
"""Check post mortem debugging works when tests fail or error"""
3320
class TracebackRecordingResult(tests.ExtendedTestResult):
3322
tests.ExtendedTestResult.__init__(self, StringIO(), 0, 1)
3323
self.postcode = None
3324
def _post_mortem(self, tb=None):
3325
"""Record the code object at the end of the current traceback"""
3326
tb = tb or sys.exc_info()[2]
3329
while next is not None:
3332
self.postcode = tb.tb_frame.f_code
3333
def report_error(self, test, err):
3335
def report_failure(self, test, err):
3338
def test_location_unittest_error(self):
3339
"""Needs right post mortem traceback with erroring unittest case"""
3340
class Test(unittest.TestCase):
3343
result = self.TracebackRecordingResult()
3345
self.assertEqual(result.postcode, Test.runTest.func_code)
3347
def test_location_unittest_failure(self):
3348
"""Needs right post mortem traceback with failing unittest case"""
3349
class Test(unittest.TestCase):
3351
raise self.failureException
3352
result = self.TracebackRecordingResult()
3354
self.assertEqual(result.postcode, Test.runTest.func_code)
3356
def test_location_bt_error(self):
3357
"""Needs right post mortem traceback with erroring bzrlib.tests case"""
3358
class Test(tests.TestCase):
3359
def test_error(self):
3361
result = self.TracebackRecordingResult()
3362
Test("test_error").run(result)
3363
self.assertEqual(result.postcode, Test.test_error.func_code)
3365
def test_location_bt_failure(self):
3366
"""Needs right post mortem traceback with failing bzrlib.tests case"""
3367
class Test(tests.TestCase):
3368
def test_failure(self):
3369
raise self.failureException
3370
result = self.TracebackRecordingResult()
3371
Test("test_failure").run(result)
3372
self.assertEqual(result.postcode, Test.test_failure.func_code)
3374
def test_env_var_triggers_post_mortem(self):
3375
"""Check pdb.post_mortem is called iff BZR_TEST_PDB is set"""
3377
result = tests.ExtendedTestResult(StringIO(), 0, 1)
3378
post_mortem_calls = []
3379
self.overrideAttr(pdb, "post_mortem", post_mortem_calls.append)
3380
self.overrideEnv('BZR_TEST_PDB', None)
3381
result._post_mortem(1)
3382
self.overrideEnv('BZR_TEST_PDB', 'on')
3383
result._post_mortem(2)
3384
self.assertEqual([2], post_mortem_calls)
2963
3387
class TestRunSuite(tests.TestCase):
2965
3389
def test_runner_class(self):
2976
3400
self.verbosity)
2977
3401
tests.run_suite(suite, runner_class=MyRunner, stream=StringIO())
2978
3402
self.assertLength(1, calls)
3405
class TestEnvironHandling(tests.TestCase):
3407
def test_overrideEnv_None_called_twice_doesnt_leak(self):
3408
self.failIf('MYVAR' in os.environ)
3409
self.overrideEnv('MYVAR', '42')
3410
# We use an embedded test to make sure we fix the _captureVar bug
3411
class Test(tests.TestCase):
3413
# The first call save the 42 value
3414
self.overrideEnv('MYVAR', None)
3415
self.assertEquals(None, os.environ.get('MYVAR'))
3416
# Make sure we can call it twice
3417
self.overrideEnv('MYVAR', None)
3418
self.assertEquals(None, os.environ.get('MYVAR'))
3420
result = tests.TextTestResult(output, 0, 1)
3421
Test('test_me').run(result)
3422
if not result.wasStrictlySuccessful():
3423
self.fail(output.getvalue())
3424
# We get our value back
3425
self.assertEquals('42', os.environ.get('MYVAR'))
3428
class TestIsolatedEnv(tests.TestCase):
3429
"""Test isolating tests from os.environ.
3431
Since we use tests that are already isolated from os.environ a bit of care
3432
should be taken when designing the tests to avoid bootstrap side-effects.
3433
The tests start an already clean os.environ which allow doing valid
3434
assertions about which variables are present or not and design tests around
3438
class ScratchMonkey(tests.TestCase):
3443
def test_basics(self):
3444
# Make sure we know the definition of BZR_HOME: not part of os.environ
3445
# for tests.TestCase.
3446
self.assertTrue('BZR_HOME' in tests.isolated_environ)
3447
self.assertEquals(None, tests.isolated_environ['BZR_HOME'])
3448
# Being part of isolated_environ, BZR_HOME should not appear here
3449
self.assertFalse('BZR_HOME' in os.environ)
3450
# Make sure we know the definition of LINES: part of os.environ for
3452
self.assertTrue('LINES' in tests.isolated_environ)
3453
self.assertEquals('25', tests.isolated_environ['LINES'])
3454
self.assertEquals('25', os.environ['LINES'])
3456
def test_injecting_unknown_variable(self):
3457
# BZR_HOME is known to be absent from os.environ
3458
test = self.ScratchMonkey('test_me')
3459
tests.override_os_environ(test, {'BZR_HOME': 'foo'})
3460
self.assertEquals('foo', os.environ['BZR_HOME'])
3461
tests.restore_os_environ(test)
3462
self.assertFalse('BZR_HOME' in os.environ)
3464
def test_injecting_known_variable(self):
3465
test = self.ScratchMonkey('test_me')
3466
# LINES is known to be present in os.environ
3467
tests.override_os_environ(test, {'LINES': '42'})
3468
self.assertEquals('42', os.environ['LINES'])
3469
tests.restore_os_environ(test)
3470
self.assertEquals('25', os.environ['LINES'])
3472
def test_deleting_variable(self):
3473
test = self.ScratchMonkey('test_me')
3474
# LINES is known to be present in os.environ
3475
tests.override_os_environ(test, {'LINES': None})
3476
self.assertTrue('LINES' not in os.environ)
3477
tests.restore_os_environ(test)
3478
self.assertEquals('25', os.environ['LINES'])
3481
class TestDocTestSuiteIsolation(tests.TestCase):
3482
"""Test that `tests.DocTestSuite` isolates doc tests from os.environ.
3484
Since tests.TestCase alreay provides an isolation from os.environ, we use
3485
the clean environment as a base for testing. To precisely capture the
3486
isolation provided by tests.DocTestSuite, we use doctest.DocTestSuite to
3489
We want to make sure `tests.DocTestSuite` respect `tests.isolated_environ`,
3490
not `os.environ` so each test overrides it to suit its needs.
3494
def get_doctest_suite_for_string(self, klass, string):
3495
class Finder(doctest.DocTestFinder):
3497
def find(*args, **kwargs):
3498
test = doctest.DocTestParser().get_doctest(
3499
string, {}, 'foo', 'foo.py', 0)
3502
suite = klass(test_finder=Finder())
3505
def run_doctest_suite_for_string(self, klass, string):
3506
suite = self.get_doctest_suite_for_string(klass, string)
3508
result = tests.TextTestResult(output, 0, 1)
3510
return result, output
3512
def assertDocTestStringSucceds(self, klass, string):
3513
result, output = self.run_doctest_suite_for_string(klass, string)
3514
if not result.wasStrictlySuccessful():
3515
self.fail(output.getvalue())
3517
def assertDocTestStringFails(self, klass, string):
3518
result, output = self.run_doctest_suite_for_string(klass, string)
3519
if result.wasStrictlySuccessful():
3520
self.fail(output.getvalue())
3522
def test_injected_variable(self):
3523
self.overrideAttr(tests, 'isolated_environ', {'LINES': '42'})
3526
>>> os.environ['LINES']
3529
# doctest.DocTestSuite fails as it sees '25'
3530
self.assertDocTestStringFails(doctest.DocTestSuite, test)
3531
# tests.DocTestSuite sees '42'
3532
self.assertDocTestStringSucceds(tests.IsolatedDocTestSuite, test)
3534
def test_deleted_variable(self):
3535
self.overrideAttr(tests, 'isolated_environ', {'LINES': None})
3538
>>> os.environ.get('LINES')
3540
# doctest.DocTestSuite fails as it sees '25'
3541
self.assertDocTestStringFails(doctest.DocTestSuite, test)
3542
# tests.DocTestSuite sees None
3543
self.assertDocTestStringSucceds(tests.IsolatedDocTestSuite, test)