835
852
self.assertContainsRe(output,
836
853
r"LSProf output for <type 'unicode'>\(\('world',\), {'errors': 'replace'}\)\n")
855
def test_uses_time_from_testtools(self):
856
"""Test case timings in verbose results should use testtools times"""
858
class TimeAddedVerboseTestResult(tests.VerboseTestResult):
859
def startTest(self, test):
860
self.time(datetime.datetime.utcfromtimestamp(1.145))
861
super(TimeAddedVerboseTestResult, self).startTest(test)
862
def addSuccess(self, test):
863
self.time(datetime.datetime.utcfromtimestamp(51.147))
864
super(TimeAddedVerboseTestResult, self).addSuccess(test)
865
def report_tests_starting(self): pass
867
self.get_passing_test().run(TimeAddedVerboseTestResult(sio, 0, 2))
868
self.assertEndsWith(sio.getvalue(), "OK 50002ms\n")
838
870
def test_known_failure(self):
839
871
"""A KnownFailure being raised should trigger several result actions."""
840
872
class InstrumentedTestResult(tests.ExtendedTestResult):
841
873
def stopTestRun(self): pass
842
def startTests(self): pass
843
def report_test_start(self, test): pass
874
def report_tests_starting(self): pass
844
875
def report_known_failure(self, test, err=None, details=None):
845
876
self._call = test, 'known failure'
846
877
result = InstrumentedTestResult(None, None, None, None)
1213
1254
self.assertContainsRe(output_string, "--date [0-9.]+")
1214
1255
self.assertLength(1, self._get_source_tree_calls)
1257
def test_verbose_test_count(self):
1258
"""A verbose test run reports the right test count at the start"""
1259
suite = TestUtil.TestSuite([
1260
unittest.FunctionTestCase(lambda:None),
1261
unittest.FunctionTestCase(lambda:None)])
1262
self.assertEqual(suite.countTestCases(), 2)
1264
runner = tests.TextTestRunner(stream=stream, verbosity=2)
1265
# Need to use the CountingDecorator as that's what sets num_tests
1266
result = self.run_test_runner(runner, tests.CountingDecorator(suite))
1267
self.assertStartsWith(stream.getvalue(), "running 2 tests")
1216
1269
def test_startTestRun(self):
1217
1270
"""run should call result.startTestRun()"""
1219
class LoggingDecorator(tests.ForwardingResult):
1272
class LoggingDecorator(ExtendedToOriginalDecorator):
1220
1273
def startTestRun(self):
1221
tests.ForwardingResult.startTestRun(self)
1274
ExtendedToOriginalDecorator.startTestRun(self)
1222
1275
calls.append('startTestRun')
1223
1276
test = unittest.FunctionTestCase(lambda:None)
1224
1277
stream = StringIO()
1655
1708
self.assertEqual('original', obj.test_attr)
1711
class _MissingFeature(tests.Feature):
1714
missing_feature = _MissingFeature()
1717
def _get_test(name):
1718
"""Get an instance of a specific example test.
1720
We protect this in a function so that they don't auto-run in the test
1724
class ExampleTests(tests.TestCase):
1726
def test_fail(self):
1727
mutter('this was a failing test')
1728
self.fail('this test will fail')
1730
def test_error(self):
1731
mutter('this test errored')
1732
raise RuntimeError('gotcha')
1734
def test_missing_feature(self):
1735
mutter('missing the feature')
1736
self.requireFeature(missing_feature)
1738
def test_skip(self):
1739
mutter('this test will be skipped')
1740
raise tests.TestSkipped('reason')
1742
def test_success(self):
1743
mutter('this test succeeds')
1745
def test_xfail(self):
1746
mutter('test with expected failure')
1747
self.knownFailure('this_fails')
1749
def test_unexpected_success(self):
1750
mutter('test with unexpected success')
1751
self.expectFailure('should_fail', lambda: None)
1753
return ExampleTests(name)
1756
class TestTestCaseLogDetails(tests.TestCase):
1758
def _run_test(self, test_name):
1759
test = _get_test(test_name)
1760
result = testtools.TestResult()
1764
def test_fail_has_log(self):
1765
result = self._run_test('test_fail')
1766
self.assertEqual(1, len(result.failures))
1767
result_content = result.failures[0][1]
1768
self.assertContainsRe(result_content, 'Text attachment: log')
1769
self.assertContainsRe(result_content, 'this was a failing test')
1771
def test_error_has_log(self):
1772
result = self._run_test('test_error')
1773
self.assertEqual(1, len(result.errors))
1774
result_content = result.errors[0][1]
1775
self.assertContainsRe(result_content, 'Text attachment: log')
1776
self.assertContainsRe(result_content, 'this test errored')
1778
def test_skip_has_no_log(self):
1779
result = self._run_test('test_skip')
1780
self.assertEqual(['reason'], result.skip_reasons.keys())
1781
skips = result.skip_reasons['reason']
1782
self.assertEqual(1, len(skips))
1784
self.assertFalse('log' in test.getDetails())
1786
def test_missing_feature_has_no_log(self):
1787
# testtools doesn't know about addNotSupported, so it just gets
1788
# considered as a skip
1789
result = self._run_test('test_missing_feature')
1790
self.assertEqual([missing_feature], result.skip_reasons.keys())
1791
skips = result.skip_reasons[missing_feature]
1792
self.assertEqual(1, len(skips))
1794
self.assertFalse('log' in test.getDetails())
1796
def test_xfail_has_no_log(self):
1797
result = self._run_test('test_xfail')
1798
self.assertEqual(1, len(result.expectedFailures))
1799
result_content = result.expectedFailures[0][1]
1800
self.assertNotContainsRe(result_content, 'Text attachment: log')
1801
self.assertNotContainsRe(result_content, 'test with expected failure')
1803
def test_unexpected_success_has_log(self):
1804
result = self._run_test('test_unexpected_success')
1805
self.assertEqual(1, len(result.unexpectedSuccesses))
1806
# Inconsistency, unexpectedSuccesses is a list of tests,
1807
# expectedFailures is a list of reasons?
1808
test = result.unexpectedSuccesses[0]
1809
details = test.getDetails()
1810
self.assertTrue('log' in details)
1813
class TestTestCloning(tests.TestCase):
1814
"""Tests that test cloning of TestCases (as used by multiply_tests)."""
1816
def test_cloned_testcase_does_not_share_details(self):
1817
"""A TestCase cloned with clone_test does not share mutable attributes
1818
such as details or cleanups.
1820
class Test(tests.TestCase):
1822
self.addDetail('foo', Content('text/plain', lambda: 'foo'))
1823
orig_test = Test('test_foo')
1824
cloned_test = tests.clone_test(orig_test, orig_test.id() + '(cloned)')
1825
orig_test.run(unittest.TestResult())
1826
self.assertEqual('foo', orig_test.getDetails()['foo'].iter_bytes())
1827
self.assertEqual(None, cloned_test.getDetails().get('foo'))
1829
def test_double_apply_scenario_preserves_first_scenario(self):
1830
"""Applying two levels of scenarios to a test preserves the attributes
1831
added by both scenarios.
1833
class Test(tests.TestCase):
1836
test = Test('test_foo')
1837
scenarios_x = [('x=1', {'x': 1}), ('x=2', {'x': 2})]
1838
scenarios_y = [('y=1', {'y': 1}), ('y=2', {'y': 2})]
1839
suite = tests.multiply_tests(test, scenarios_x, unittest.TestSuite())
1840
suite = tests.multiply_tests(suite, scenarios_y, unittest.TestSuite())
1841
all_tests = list(tests.iter_suite_tests(suite))
1842
self.assertLength(4, all_tests)
1843
all_xys = sorted((t.x, t.y) for t in all_tests)
1844
self.assertEqual([(1, 1), (1, 2), (2, 1), (2, 2)], all_xys)
1658
1847
# NB: Don't delete this; it's not actually from 0.11!
1659
1848
@deprecated_function(deprecated_in((0, 11, 0)))
1660
1849
def sample_deprecated_function():
1971
2160
load_list='missing file name', list_only=True)
2163
class TestSubunitLogDetails(tests.TestCase, SelfTestHelper):
2165
_test_needs_features = [features.subunit]
2167
def run_subunit_stream(self, test_name):
2168
from subunit import ProtocolTestCase
2170
return TestUtil.TestSuite([_get_test(test_name)])
2171
stream = self.run_selftest(runner_class=tests.SubUnitBzrRunner,
2172
test_suite_factory=factory)
2173
test = ProtocolTestCase(stream)
2174
result = testtools.TestResult()
2176
content = stream.getvalue()
2177
return content, result
2179
def test_fail_has_log(self):
2180
content, result = self.run_subunit_stream('test_fail')
2181
self.assertEqual(1, len(result.failures))
2182
self.assertContainsRe(content, '(?m)^log$')
2183
self.assertContainsRe(content, 'this test will fail')
2185
def test_error_has_log(self):
2186
content, result = self.run_subunit_stream('test_error')
2187
self.assertContainsRe(content, '(?m)^log$')
2188
self.assertContainsRe(content, 'this test errored')
2190
def test_skip_has_no_log(self):
2191
content, result = self.run_subunit_stream('test_skip')
2192
self.assertNotContainsRe(content, '(?m)^log$')
2193
self.assertNotContainsRe(content, 'this test will be skipped')
2194
self.assertEqual(['reason'], result.skip_reasons.keys())
2195
skips = result.skip_reasons['reason']
2196
self.assertEqual(1, len(skips))
2198
# RemotedTestCase doesn't preserve the "details"
2199
## self.assertFalse('log' in test.getDetails())
2201
def test_missing_feature_has_no_log(self):
2202
content, result = self.run_subunit_stream('test_missing_feature')
2203
self.assertNotContainsRe(content, '(?m)^log$')
2204
self.assertNotContainsRe(content, 'missing the feature')
2205
self.assertEqual(['_MissingFeature\n'], result.skip_reasons.keys())
2206
skips = result.skip_reasons['_MissingFeature\n']
2207
self.assertEqual(1, len(skips))
2209
# RemotedTestCase doesn't preserve the "details"
2210
## self.assertFalse('log' in test.getDetails())
2212
def test_xfail_has_no_log(self):
2213
content, result = self.run_subunit_stream('test_xfail')
2214
self.assertNotContainsRe(content, '(?m)^log$')
2215
self.assertNotContainsRe(content, 'test with expected failure')
2216
self.assertEqual(1, len(result.expectedFailures))
2217
result_content = result.expectedFailures[0][1]
2218
self.assertNotContainsRe(result_content, 'Text attachment: log')
2219
self.assertNotContainsRe(result_content, 'test with expected failure')
2221
def test_unexpected_success_has_log(self):
2222
content, result = self.run_subunit_stream('test_unexpected_success')
2223
self.assertContainsRe(content, '(?m)^log$')
2224
self.assertContainsRe(content, 'test with unexpected success')
2225
self.expectFailure('subunit treats "unexpectedSuccess"'
2226
' as a plain success',
2227
self.assertEqual, 1, len(result.unexpectedSuccesses))
2228
self.assertEqual(1, len(result.unexpectedSuccesses))
2229
test = result.unexpectedSuccesses[0]
2230
# RemotedTestCase doesn't preserve the "details"
2231
## self.assertTrue('log' in test.getDetails())
2233
def test_success_has_no_log(self):
2234
content, result = self.run_subunit_stream('test_success')
2235
self.assertEqual(1, result.testsRun)
2236
self.assertNotContainsRe(content, '(?m)^log$')
2237
self.assertNotContainsRe(content, 'this test succeeds')
1974
2240
class TestRunBzr(tests.TestCase):
2960
3231
self.assertEquals('bzrlib.plugins', tpr.resolve_alias('bp'))
3234
class TestThreadLeakDetection(tests.TestCase):
3235
"""Ensure when tests leak threads we detect and report it"""
3237
class LeakRecordingResult(tests.ExtendedTestResult):
3239
tests.ExtendedTestResult.__init__(self, StringIO(), 0, 1)
3241
def _report_thread_leak(self, test, leaks, alive):
3242
self.leaks.append((test, leaks))
3244
def test_testcase_without_addCleanups(self):
3245
"""Check old TestCase instances don't break with leak detection"""
3246
class Test(unittest.TestCase):
3249
addCleanup = None # for when on Python 2.7 with native addCleanup
3250
result = self.LeakRecordingResult()
3252
self.assertIs(getattr(test, "addCleanup", None), None)
3253
result.startTestRun()
3255
result.stopTestRun()
3256
self.assertEqual(result._tests_leaking_threads_count, 0)
3257
self.assertEqual(result.leaks, [])
3259
def test_thread_leak(self):
3260
"""Ensure a thread that outlives the running of a test is reported
3262
Uses a thread that blocks on an event, and is started by the inner
3263
test case. As the thread outlives the inner case's run, it should be
3264
detected as a leak, but the event is then set so that the thread can
3265
be safely joined in cleanup so it's not leaked for real.
3267
event = threading.Event()
3268
thread = threading.Thread(name="Leaker", target=event.wait)
3269
class Test(tests.TestCase):
3270
def test_leak(self):
3272
result = self.LeakRecordingResult()
3273
test = Test("test_leak")
3274
self.addCleanup(thread.join)
3275
self.addCleanup(event.set)
3276
result.startTestRun()
3278
result.stopTestRun()
3279
self.assertEqual(result._tests_leaking_threads_count, 1)
3280
self.assertEqual(result._first_thread_leaker_id, test.id())
3281
self.assertEqual(result.leaks, [(test, set([thread]))])
3282
self.assertContainsString(result.stream.getvalue(), "leaking threads")
3284
def test_multiple_leaks(self):
3285
"""Check multiple leaks are blamed on the test cases at fault
3287
Same concept as the previous test, but has one inner test method that
3288
leaks two threads, and one that doesn't leak at all.
3290
event = threading.Event()
3291
thread_a = threading.Thread(name="LeakerA", target=event.wait)
3292
thread_b = threading.Thread(name="LeakerB", target=event.wait)
3293
thread_c = threading.Thread(name="LeakerC", target=event.wait)
3294
class Test(tests.TestCase):
3295
def test_first_leak(self):
3297
def test_second_no_leak(self):
3299
def test_third_leak(self):
3302
result = self.LeakRecordingResult()
3303
first_test = Test("test_first_leak")
3304
third_test = Test("test_third_leak")
3305
self.addCleanup(thread_a.join)
3306
self.addCleanup(thread_b.join)
3307
self.addCleanup(thread_c.join)
3308
self.addCleanup(event.set)
3309
result.startTestRun()
3311
[first_test, Test("test_second_no_leak"), third_test]
3313
result.stopTestRun()
3314
self.assertEqual(result._tests_leaking_threads_count, 2)
3315
self.assertEqual(result._first_thread_leaker_id, first_test.id())
3316
self.assertEqual(result.leaks, [
3317
(first_test, set([thread_b])),
3318
(third_test, set([thread_a, thread_c]))])
3319
self.assertContainsString(result.stream.getvalue(), "leaking threads")
3322
class TestPostMortemDebugging(tests.TestCase):
3323
"""Check post mortem debugging works when tests fail or error"""
3325
class TracebackRecordingResult(tests.ExtendedTestResult):
3327
tests.ExtendedTestResult.__init__(self, StringIO(), 0, 1)
3328
self.postcode = None
3329
def _post_mortem(self, tb=None):
3330
"""Record the code object at the end of the current traceback"""
3331
tb = tb or sys.exc_info()[2]
3334
while next is not None:
3337
self.postcode = tb.tb_frame.f_code
3338
def report_error(self, test, err):
3340
def report_failure(self, test, err):
3343
def test_location_unittest_error(self):
3344
"""Needs right post mortem traceback with erroring unittest case"""
3345
class Test(unittest.TestCase):
3348
result = self.TracebackRecordingResult()
3350
self.assertEqual(result.postcode, Test.runTest.func_code)
3352
def test_location_unittest_failure(self):
3353
"""Needs right post mortem traceback with failing unittest case"""
3354
class Test(unittest.TestCase):
3356
raise self.failureException
3357
result = self.TracebackRecordingResult()
3359
self.assertEqual(result.postcode, Test.runTest.func_code)
3361
def test_location_bt_error(self):
3362
"""Needs right post mortem traceback with erroring bzrlib.tests case"""
3363
class Test(tests.TestCase):
3364
def test_error(self):
3366
result = self.TracebackRecordingResult()
3367
Test("test_error").run(result)
3368
self.assertEqual(result.postcode, Test.test_error.func_code)
3370
def test_location_bt_failure(self):
3371
"""Needs right post mortem traceback with failing bzrlib.tests case"""
3372
class Test(tests.TestCase):
3373
def test_failure(self):
3374
raise self.failureException
3375
result = self.TracebackRecordingResult()
3376
Test("test_failure").run(result)
3377
self.assertEqual(result.postcode, Test.test_failure.func_code)
3379
def test_env_var_triggers_post_mortem(self):
3380
"""Check pdb.post_mortem is called iff BZR_TEST_PDB is set"""
3382
result = tests.ExtendedTestResult(StringIO(), 0, 1)
3383
post_mortem_calls = []
3384
self.overrideAttr(pdb, "post_mortem", post_mortem_calls.append)
3385
self.addCleanup(osutils.set_or_unset_env, "BZR_TEST_PDB",
3386
osutils.set_or_unset_env("BZR_TEST_PDB", None))
3387
result._post_mortem(1)
3388
os.environ["BZR_TEST_PDB"] = "on"
3389
result._post_mortem(2)
3390
self.assertEqual([2], post_mortem_calls)
2963
3393
class TestRunSuite(tests.TestCase):
2965
3395
def test_runner_class(self):