#25406 closed Bug (fixed)
_create_test_db hides errors like 'source database "template1" is being accessed by other users' with --keepdb
Reported by: | Daniel Hahler | Owned by: | Mariusz Felisiak |
---|---|---|---|
Component: | Database layer (models, ORM) | Version: | dev |
Severity: | Normal | Keywords: | |
Cc: | felisiak.mariusz@… | Triage Stage: | Ready for checkin |
Has patch: | yes | Needs documentation: | no |
Needs tests: | no | Patch needs improvement: | no |
Easy pickings: | no | UI/UX: | no |
Description
The _create_test_db method will hide errors like 'source database "template1" is being accessed by other users', and will assume that the test database exists already.
> …/pyenv/project/lib/python3.4/site-packages/psycopg2/__init__.py(165)connect() 164 import ipdb; ipdb.set_trace() --> 165 conn = _connect(dsn, connection_factory=connection_factory, async=async) 166 if cursor_factory is not None: ipdb> c source database "template1" is being accessed by other users DETAIL: There are 3 other sessions using the database. > …/pyenv/project/lib/python3.4/site-packages/django/db/backends/base/creation.py(458)_create_test_db() 457 # just return and skip it all. --> 458 if keepdb: 459 return test_database_name
Source reference: https://github.com/blueyed/django/blob/9e530b08d5858d7063d081b60ec86d24173e4df5/django/db/backends/base/creation.py#L146-L165
This will then result in an error when trying to connect to it, because it has not been created:
psycopg2.OperationalError: FATAL: database "test_project" does not exist
But instead the initial error should be displayed:
source database "template1" is being accessed by other users
DETAIL: There are 3 other sessions using the database.
To reproduce this:
- connect to the "template1" database
- run Django tests
I think the SQL could use CREATE DATABASE IF NOT EXISTS
(in case IF NOT EXISTS
) is supported by all backends (maybe that needs to be subclassed then), and then would not assume that an Exception can be ignored with keepdb
.
An even better way would be to check if it exists, instead of trying to create it.
With pytest-django we're using the following code:
def test_database_exists_from_previous_run(connection): # Try to open a cursor to the test database test_db_name = connection.creation._get_test_db_name() # When using a real SQLite backend (via TEST_NAME), check if the file # exists, because it gets created automatically. if connection.settings_dict['ENGINE'] == 'django.db.backends.sqlite3': if not os.path.exists(test_db_name): return False orig_db_name = connection.settings_dict['NAME'] connection.settings_dict['NAME'] = test_db_name # With SQLite memory databases the db never exists. if connection.settings_dict['NAME'] == ':memory:': return False try: connection.cursor() return True except Exception: # TODO: Be more discerning but still DB agnostic. return False finally: connection.close() connection.settings_dict['NAME'] = orig_db_name
Change History (8)
comment:1 by , 9 years ago
comment:3 by , 8 years ago
Another example is "ProgrammingError: permission denied to create database".
I think an easy improvement would be to log the exception always.
And/or really check if the database exists already when skipping it for "keepdb".
Is it possible to use "CREATE DABASE ... IF NOT EXISTS" or something similar here?
comment:4 by , 8 years ago
Cc: | added |
---|---|
Owner: | changed from | to
Status: | new → assigned |
comment:6 by , 8 years ago
Triage Stage: | Accepted → Ready for checkin |
---|
(just for reference: I've noticed this when making pytest-django use Django's
keepdb
method - https://github.com/pytest-dev/pytest-django/pull/261)