#36770: SQLite threading tests are flaky when parallel test suite runs in
forkserver mode
-------------------------------------+-------------------------------------
     Reporter:  Jacob Walls          |                    Owner:  Kundan
         Type:                       |  Yadav
  Cleanup/optimization               |                   Status:  assigned
    Component:  Testing framework    |                  Version:  5.2
     Severity:  Normal               |               Resolution:
     Keywords:  3.14, forkserver,    |             Triage Stage:  Accepted
  parallel                           |
    Has patch:  0                    |      Needs documentation:  0
  Needs tests:  0                    |  Patch needs improvement:  0
Easy pickings:  0                    |                    UI/UX:  0
-------------------------------------+-------------------------------------
Comment (by Jacob Walls):

 I've seen this intermittently locally. Leaving aside the assertion
 failures for SQLite, we shouldn't have a hang in `LiveServerTestCase` when
 tests fail. You can engineer a hang like this, setting a miniscule timeout
 that will always raise:

 {{{#!py
 diff --git a/django/test/testcases.py b/django/test/testcases.py
 index 5f83612fe5..622b938dd6 100644
 --- a/django/test/testcases.py
 +++ b/django/test/testcases.py
 @@ -1844,7 +1844,8 @@ class LiveServerTestCase(TransactionTestCase):
          cls.addClassCleanup(cls._terminate_thread)

          # Wait for the live server to be ready
 -        cls.server_thread.is_ready.wait()
 +        if not cls.server_thread.is_ready.wait(timeout=0.001):
 +            raise Exception("Live server never became ready.")
          if cls.server_thread.error:
              raise cls.server_thread.error
 }}}


 Then when `KeyboardInterrupt`ing out of it, you get a stack trace from
 `doClassCleanups`, suggesting that the termination code is waiting
 forever, even though the live server never started:

 {{{#!py
   File
 
"/Library/Frameworks/Python.framework/Versions/3.14/lib/python3.14/unittest/suite.py",
 line 181, in _handleClassSetUp
     doClassCleanups()
     ~~~~~~~~~~~~~~~^^
   File
 
"/Library/Frameworks/Python.framework/Versions/3.14/lib/python3.14/unittest/case.py",
 line 720, in doClassCleanups
     function(*args, **kwargs)
     ~~~~~~~~^^^^^^^^^^^^^^^^^
   File "/Users/jwalls/django/django/test/testcases.py", line 1864, in
 _terminate_thread
     cls.server_thread.terminate()
     ~~~~~~~~~~~~~~~~~~~~~~~~~~~^^
   File "/Users/jwalls/django/django/test/testcases.py", line 1788, in
 terminate
     self.join()
 }}}

 Something like this fixes it:

 {{{#!diff
 diff --git a/django/test/testcases.py b/django/test/testcases.py
 index 5f83612fe5..9cbeeeca25 100644
 --- a/django/test/testcases.py
 +++ b/django/test/testcases.py
 @@ -1781,11 +1781,12 @@ class LiveServerThread(threading.Thread):
          )

      def terminate(self):
 -        if hasattr(self, "httpd"):
 -            # Stop the WSGI server
 -            self.httpd.shutdown()
 -            self.httpd.server_close()
 -        self.join()
 +        if self.is_ready.is_set():
 +            if hasattr(self, "httpd"):
 +                # Stop the WSGI server
 +                self.httpd.shutdown()
 +                self.httpd.server_close()
 +            self.join()
 }}}

 My theory is that the "live server never became ready" situation I
 simulated above is similar to the situation we're seeing on CI where a
 database lock entails a failure to start a live server thread.
 ----
 Then for one of the underlying assertion failures, I don't know how I feel
 about masking a real problem, but we could probably reduce the chance of
 failing jobs by adjusting `test_in_memory_database_lock()` to use the
 `other` database instead of the `default`. It would still cover the code
 it's testing, but it would just have a much smaller chance of interacting
 poorly with other tests.
-- 
Ticket URL: <https://code.djangoproject.com/ticket/36770#comment:4>
Django <https://code.djangoproject.com/>
The Web framework for perfectionists with deadlines.

-- 
You received this message because you are subscribed to the Google Groups 
"Django updates" group.
To unsubscribe from this group and stop receiving emails from it, send an email 
to [email protected].
To view this discussion visit 
https://groups.google.com/d/msgid/django-updates/0107019c4d7c001f-5bbd5c26-458d-4681-8455-c7ab6b156d90-000000%40eu-central-1.amazonses.com.

Reply via email to