1. import pickle
    
  2. import sys
    
  3. import unittest
    
  4. 
    
  5. from django.test import SimpleTestCase
    
  6. from django.test.runner import RemoteTestResult
    
  7. from django.utils.version import PY311
    
  8. 
    
  9. try:
    
  10.     import tblib.pickling_support
    
  11. except ImportError:
    
  12.     tblib = None
    
  13. 
    
  14. 
    
  15. class ExceptionThatFailsUnpickling(Exception):
    
  16.     """
    
  17.     After pickling, this class fails unpickling with an error about incorrect
    
  18.     arguments passed to __init__().
    
  19.     """
    
  20. 
    
  21.     def __init__(self, arg):
    
  22.         super().__init__()
    
  23. 
    
  24. 
    
  25. class ParallelTestRunnerTest(SimpleTestCase):
    
  26.     """
    
  27.     End-to-end tests of the parallel test runner.
    
  28. 
    
  29.     These tests are only meaningful when running tests in parallel using
    
  30.     the --parallel option, though it doesn't hurt to run them not in
    
  31.     parallel.
    
  32.     """
    
  33. 
    
  34.     def test_subtest(self):
    
  35.         """
    
  36.         Passing subtests work.
    
  37.         """
    
  38.         for i in range(2):
    
  39.             with self.subTest(index=i):
    
  40.                 self.assertEqual(i, i)
    
  41. 
    
  42. 
    
  43. class SampleFailingSubtest(SimpleTestCase):
    
  44.     # This method name doesn't begin with "test" to prevent test discovery
    
  45.     # from seeing it.
    
  46.     def dummy_test(self):
    
  47.         """
    
  48.         A dummy test for testing subTest failures.
    
  49.         """
    
  50.         for i in range(3):
    
  51.             with self.subTest(index=i):
    
  52.                 self.assertEqual(i, 1)
    
  53. 
    
  54. 
    
  55. class RemoteTestResultTest(SimpleTestCase):
    
  56.     def _test_error_exc_info(self):
    
  57.         try:
    
  58.             raise ValueError("woops")
    
  59.         except ValueError:
    
  60.             return sys.exc_info()
    
  61. 
    
  62.     def test_was_successful_no_events(self):
    
  63.         result = RemoteTestResult()
    
  64.         self.assertIs(result.wasSuccessful(), True)
    
  65. 
    
  66.     def test_was_successful_one_success(self):
    
  67.         result = RemoteTestResult()
    
  68.         result.addSuccess(None)
    
  69.         self.assertIs(result.wasSuccessful(), True)
    
  70. 
    
  71.     def test_was_successful_one_expected_failure(self):
    
  72.         result = RemoteTestResult()
    
  73.         result.addExpectedFailure(None, self._test_error_exc_info())
    
  74.         self.assertIs(result.wasSuccessful(), True)
    
  75. 
    
  76.     def test_was_successful_one_skip(self):
    
  77.         result = RemoteTestResult()
    
  78.         result.addSkip(None, "Skipped")
    
  79.         self.assertIs(result.wasSuccessful(), True)
    
  80. 
    
  81.     @unittest.skipUnless(tblib is not None, "requires tblib to be installed")
    
  82.     def test_was_successful_one_error(self):
    
  83.         result = RemoteTestResult()
    
  84.         result.addError(None, self._test_error_exc_info())
    
  85.         self.assertIs(result.wasSuccessful(), False)
    
  86. 
    
  87.     @unittest.skipUnless(tblib is not None, "requires tblib to be installed")
    
  88.     def test_was_successful_one_failure(self):
    
  89.         result = RemoteTestResult()
    
  90.         result.addFailure(None, self._test_error_exc_info())
    
  91.         self.assertIs(result.wasSuccessful(), False)
    
  92. 
    
  93.     def test_picklable(self):
    
  94.         result = RemoteTestResult()
    
  95.         loaded_result = pickle.loads(pickle.dumps(result))
    
  96.         self.assertEqual(result.events, loaded_result.events)
    
  97. 
    
  98.     def test_pickle_errors_detection(self):
    
  99.         picklable_error = RuntimeError("This is fine")
    
  100.         not_unpicklable_error = ExceptionThatFailsUnpickling("arg")
    
  101. 
    
  102.         result = RemoteTestResult()
    
  103.         result._confirm_picklable(picklable_error)
    
  104. 
    
  105.         msg = "__init__() missing 1 required positional argument"
    
  106.         with self.assertRaisesMessage(TypeError, msg):
    
  107.             result._confirm_picklable(not_unpicklable_error)
    
  108. 
    
  109.     @unittest.skipUnless(tblib is not None, "requires tblib to be installed")
    
  110.     def test_add_failing_subtests(self):
    
  111.         """
    
  112.         Failing subtests are added correctly using addSubTest().
    
  113.         """
    
  114.         # Manually run a test with failing subtests to prevent the failures
    
  115.         # from affecting the actual test run.
    
  116.         result = RemoteTestResult()
    
  117.         subtest_test = SampleFailingSubtest(methodName="dummy_test")
    
  118.         subtest_test.run(result=result)
    
  119. 
    
  120.         events = result.events
    
  121.         self.assertEqual(len(events), 4)
    
  122.         self.assertIs(result.wasSuccessful(), False)
    
  123. 
    
  124.         event = events[1]
    
  125.         self.assertEqual(event[0], "addSubTest")
    
  126.         self.assertEqual(
    
  127.             str(event[2]),
    
  128.             "dummy_test (test_runner.test_parallel.SampleFailingSubtest%s) (index=0)"
    
  129.             # Python 3.11 uses fully qualified test name in the output.
    
  130.             % (".dummy_test" if PY311 else ""),
    
  131.         )
    
  132.         self.assertEqual(repr(event[3][1]), "AssertionError('0 != 1')")
    
  133. 
    
  134.         event = events[2]
    
  135.         self.assertEqual(repr(event[3][1]), "AssertionError('2 != 1')")