Opened 113 minutes ago
Last modified 97 minutes ago
#36946 new Bug
Running tests on SQLite with --parallel (using spawn) does not respect DATABASES["TEST"]["NAME"]
| Reported by: | Sage Abdullah | Owned by: | |
|---|---|---|---|
| Component: | Testing framework | Version: | dev |
| Severity: | Normal | Keywords: | tests, sqlite, parallel |
| Cc: | Sage Abdullah | Triage Stage: | Accepted |
| Has patch: | yes | Needs documentation: | no |
| Needs tests: | no | Patch needs improvement: | no |
| Easy pickings: | no | UI/UX: | no |
Description
When running unit tests on SQLite on macOS with the --parallel flag and the DATABASES["TEST"]["NAME"] setting set (e.g. to mytests.db), the tests fail to run because SQLite tries to connect to databases named default_*.sqlite3 instead of the cloned mytests_*.db.
You can replicate this with the Django test suite itself, e.g. with the following change:
-
tests/test_sqlite.py
diff --git a/tests/test_sqlite.py b/tests/test_sqlite.py index 0e6b0f672a..77981218fd 100644
a b PASSWORD_HASHERS = [ 29 29 ] 30 30 31 31 USE_TZ = False 32 33 import os 34 35 DATABASE_NAME = os.getenv("DATABASE_NAME") 36 if DATABASE_NAME: 37 DATABASES["default"]["TEST"] = {"NAME": DATABASE_NAME}
and then run a subset of the tests, e.g.
DATABASE_NAME=django.db ./runtests.py --verbosity=2 --parallel=2 -- model_fields
You'll get a bunch of errors like the following:
Traceback (most recent call last): File "/../python/3.14.2/lib/python3.14/multiprocessing/process.py", line 320, in _bootstrap self.run() ~~~~~~~~^^ File "/../python/3.14.2/lib/python3.14/multiprocessing/process.py", line 108, in run self._target(*self._args, **self._kwargs) ~~~~~~~~~~~~^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ File "/../python/3.14.2/lib/python3.14/multiprocessing/pool.py", line 109, in worker initializer(*initargs) ~~~~~~~~~~~^^^^^^^^^^^ File "/django/django/test/runner.py", line 479, in _safe_init_worker init_worker(counter, *args, **kwargs) ~~~~~~~~~~~^^^^^^^^^^^^^^^^^^^^^^^^^^ File "/django/django/test/runner.py", line 464, in _init_worker connection.creation.setup_worker_connection(_worker_id) ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~^^^^^^^^^^^^ File "/django/django/db/backends/sqlite3/creation.py", line 145, in setup_worker_connection source_db = self.connection.Database.connect( f"file:{alias}_{_worker_id}.sqlite3?mode=ro", uri=True ) sqlite3.OperationalError: unable to open database file
but you can see that Django successfully created/destroyed the test databases with the correct names:
Cloning test database for alias 'default' ('django.db')... Cloning test database for alias 'default' ('django.db')... # test results go here Destroying test database for alias 'default' ('django_1.db')... Destroying test database for alias 'default' ('django_2.db')... Destroying test database for alias 'default' ('django.db')...
This also affects a multi-database setup if you set the ["TEST"]["NAME"] for that database. With the above example, if you run the multiple_database test suite (instead of model_fields), you won't see any errors for the other database; as Django will create and connect to the fallback test name based on the alias, i.e. other_*.sqlite3. However, if you also add DATABASES["other"]["TEST"] = {"NAME": "other_" + DATABASE_NAME} to the settings changes in the above example, the same error now also happens for the other database.
This prevents the use of custom names for running tests with --parallel > 1 (or auto), which can be particularly useful when you want to use --keepdb with different names. With --parallel=1, this issue does not occur.
I believe it is because despite the cloning was done correctly using the given test database file name in get_test_db_clone_settings, the logic in setup_worker_connection does not use the clone db names (it always uses {alias}_{_worker_id}.sqlite3 instead) when copying them over to the in-memory database.
FWIW, I encountered this while trying to run Wagtail's test suite in parallel with --keepdb. I can give a smaller reproducible example if necessary, but I think the example with Django's own test suite can be a good example too.
Attachments (1)
Change History (2)
by , 113 minutes ago
| Attachment: | sqlite_setup_worker_connection_fix.diff added |
|---|
comment:1 by , 97 minutes ago
| Triage Stage: | Unreviewed → Accepted |
|---|
Thanks Sage, I suspected this was not handled but hadn't yet verified. Would you like to submit a PR?
Related: I've noticed we have the same
OperationalErrorwhen a parallel test worker dies. In that case, the worker_id increments past the number of databases, and a connection is requested for a nonexistent database. At a glance, it looks like your suggested patch fixes that as well.