﻿id	summary	reporter	owner	description	type	status	component	version	severity	resolution	keywords	cc	stage	has_patch	needs_docs	needs_tests	needs_better_patch	easy	ui_ux
31055	Omits test_ prefix from database name when running subset of tests	Matthijs Kooijman	Simon Charette	"While debugging some test framework issues wrt mysql, I noticed a problem where the test runner would try to access the test database without prefixing `test_`, leading to an access denied error (because my permissions are set up tightly).

What I suspect happens is that this subset of tests only uses the `default` database, so only that one is set up by `DisoveryRunner.setup_databases`. This is confirmed by using a debugger, which shows [[https://github.com/django/django/blob/845042b3d9faaefef8855c2bab48bd9532cd00ca/django/test/runner.py#L683|databases]] only contains 'default'. Then, it runs the `check` management command, which looks at `settings.DATABASES`, which still contains the settings for `default` and `other`. This in turn causes a connection to the `other` database to be made, but since the name of that database is not modified by [[https://github.com/django/django/blob/845042b3d9faaefef8855c2bab48bd9532cd00ca/django/db/backends/base/creation.py#L61|create_test_db]], that still refers to the original name, and the connection fails.

To reproduce, I have a clean master (c33eb6dcd0c211f8f02b2976fe3b3463f0a54498), with the following `tests/test_mysql.py`:

{{{
DATABASES = {                                                                                                           
    'default': {                                                                                                        
        'ENGINE': 'django.db.backends.mysql',                                                                           
        'HOST': 'localhost',                                                                                            
        'USER': 'test_django',                                                                                          
        'PASSWORD': 'XXX',                                                                                 
        # Django prepends test_ to this name...                                                                         
        'NAME': 'django_main',                                                                                          
    },                                                                                                                  
    'other': {                                                                                                          
        'ENGINE': 'django.db.backends.mysql',                                                                           
        'HOST': 'localhost',                                                                                            
        'USER': 'test_django',                                                                                          
        'PASSWORD': 'XXX',                                                                                 
        # Django prepends test_ to this name...                                                                         
        'NAME': 'django_other',                                                                                         
    }                                                                                                                   
}                                                                                                                       
                                                                                                                        
SECRET_KEY = ""django_tests_secret_key""                                                                                  
                                                                                                                        
# Use a fast hasher to speed up tests.                                                                                  
PASSWORD_HASHERS = [                                                                                                    
    'django.contrib.auth.hashers.MD5PasswordHasher',                                                                    
]
}}}

Then inside `tests`, I run:

{{{
 ./runtests.py --settings test_mysql --parallel 1 timezones 
}}}

I think the `--parallel 1` is not strictly needed, but might make things easier to debug. With the above, I get:

{{{
Creating test database for alias 'default'...
Destroying test database for alias 'default'...
Testing against Django installed in '/home/matthijs/docs/src/upstream/django/django'
Traceback (most recent call last):
  File ""/home/matthijs/docs/src/upstream/django/django/db/backends/base/base.py"", line 220, in ensure_connection
    self.connect()
  File ""/home/matthijs/docs/src/upstream/django/django/utils/asyncio.py"", line 24, in inner
    return func(*args, **kwargs)
  File ""/home/matthijs/docs/src/upstream/django/django/db/backends/base/base.py"", line 197, in connect
    self.connection = self.get_new_connection(conn_params)
  File ""/home/matthijs/docs/src/upstream/django/django/utils/asyncio.py"", line 24, in inner
    return func(*args, **kwargs)
  File ""/home/matthijs/docs/src/upstream/django/django/db/backends/mysql/base.py"", line 233, in get_new_connection
    return Database.connect(**conn_params)
  File ""/home/matthijs/docs/src/upstream/django/venv/lib/python3.7/site-packages/MySQLdb/__init__.py"", line 84, in Connect
    return Connection(*args, **kwargs)
  File ""/home/matthijs/docs/src/upstream/django/venv/lib/python3.7/site-packages/MySQLdb/connections.py"", line 179, in __init__
    super(Connection, self).__init__(*args, **kwargs2)
MySQLdb._exceptions.OperationalError: (1044, ""Access denied for user 'test_django'@'localhost' to database 'django_other'"")

The above exception was the direct cause of the following exception:

Traceback (most recent call last):
  File ""./runtests.py"", line 566, in <module>
    options.start_at, options.start_after, options.pdb,
  File ""./runtests.py"", line 308, in django_tests
    extra_tests=extra_tests,
  File ""/home/matthijs/docs/src/upstream/django/django/test/runner.py"", line 687, in run_tests
    self.run_checks()
  File ""/home/matthijs/docs/src/upstream/django/django/test/runner.py"", line 625, in run_checks
    call_command('check', verbosity=self.verbosity)
  File ""/home/matthijs/docs/src/upstream/django/django/core/management/__init__.py"", line 168, in call_command
    return command.execute(*args, **defaults)
  File ""/home/matthijs/docs/src/upstream/django/django/core/management/base.py"", line 369, in execute
    output = self.handle(*args, **options)
  File ""/home/matthijs/docs/src/upstream/django/django/core/management/commands/check.py"", line 64, in handle
    fail_level=getattr(checks, options['fail_level']),
  File ""/home/matthijs/docs/src/upstream/django/django/core/management/base.py"", line 395, in check
    include_deployment_checks=include_deployment_checks,
  File ""/home/matthijs/docs/src/upstream/django/django/core/management/base.py"", line 382, in _run_checks
    return checks.run_checks(**kwargs)
  File ""/home/matthijs/docs/src/upstream/django/django/core/checks/registry.py"", line 72, in run_checks
    new_errors = check(app_configs=app_configs)
  File ""/home/matthijs/docs/src/upstream/django/django/core/checks/model_checks.py"", line 34, in check_all_models
    errors.extend(model.check(**kwargs))
  File ""/home/matthijs/docs/src/upstream/django/django/db/models/base.py"", line 1276, in check
    *cls._check_constraints(),
  File ""/home/matthijs/docs/src/upstream/django/django/db/models/base.py"", line 1842, in _check_constraints
    connection.features.supports_table_check_constraints or
  File ""/home/matthijs/docs/src/upstream/django/django/utils/functional.py"", line 48, in __get__
    res = instance.__dict__[self.name] = self.func(instance)
  File ""/home/matthijs/docs/src/upstream/django/django/db/backends/mysql/features.py"", line 97, in supports_column_check_constraints
    if self.connection.mysql_is_mariadb:
  File ""/home/matthijs/docs/src/upstream/django/django/utils/functional.py"", line 48, in __get__
    res = instance.__dict__[self.name] = self.func(instance)
  File ""/home/matthijs/docs/src/upstream/django/django/db/backends/mysql/base.py"", line 364, in mysql_is_mariadb
    return 'mariadb' in self.mysql_server_info.lower()
  File ""/home/matthijs/docs/src/upstream/django/django/utils/functional.py"", line 48, in __get__
    res = instance.__dict__[self.name] = self.func(instance)
  File ""/home/matthijs/docs/src/upstream/django/django/db/backends/mysql/base.py"", line 351, in mysql_server_info
    with self.temporary_connection() as cursor:
  File ""/usr/lib/python3.7/contextlib.py"", line 112, in __enter__
    return next(self.gen)
  File ""/home/matthijs/docs/src/upstream/django/django/db/backends/base/base.py"", line 604, in temporary_connection
    with self.cursor() as cursor:
  File ""/home/matthijs/docs/src/upstream/django/django/utils/asyncio.py"", line 24, in inner
    return func(*args, **kwargs)
  File ""/home/matthijs/docs/src/upstream/django/django/db/backends/base/base.py"", line 260, in cursor
    return self._cursor()
  File ""/home/matthijs/docs/src/upstream/django/django/db/backends/base/base.py"", line 236, in _cursor
    self.ensure_connection()
  File ""/home/matthijs/docs/src/upstream/django/django/utils/asyncio.py"", line 24, in inner
    return func(*args, **kwargs)
  File ""/home/matthijs/docs/src/upstream/django/django/db/backends/base/base.py"", line 220, in ensure_connection
    self.connect()
  File ""/home/matthijs/docs/src/upstream/django/django/db/utils.py"", line 90, in __exit__
    raise dj_exc_value.with_traceback(traceback) from exc_value
  File ""/home/matthijs/docs/src/upstream/django/django/db/backends/base/base.py"", line 220, in ensure_connection
    self.connect()
  File ""/home/matthijs/docs/src/upstream/django/django/utils/asyncio.py"", line 24, in inner
    return func(*args, **kwargs)
  File ""/home/matthijs/docs/src/upstream/django/django/db/backends/base/base.py"", line 197, in connect
    self.connection = self.get_new_connection(conn_params)
  File ""/home/matthijs/docs/src/upstream/django/django/utils/asyncio.py"", line 24, in inner
    return func(*args, **kwargs)
  File ""/home/matthijs/docs/src/upstream/django/django/db/backends/mysql/base.py"", line 233, in get_new_connection
    return Database.connect(**conn_params)
  File ""/home/matthijs/docs/src/upstream/django/venv/lib/python3.7/site-packages/MySQLdb/__init__.py"", line 84, in Connect
    return Connection(*args, **kwargs)
  File ""/home/matthijs/docs/src/upstream/django/venv/lib/python3.7/site-packages/MySQLdb/connections.py"", line 179, in __init__
    super(Connection, self).__init__(*args, **kwargs2)
django.db.utils.OperationalError: (1044, ""Access denied for user 'test_django'@'localhost' to database 'django_other'"")
}}}

I am not quite familiar with this code, and this is already a distraction from a distraction from a distraction from the actual project I was working on, so I'm going to leave this here for others to fix :-)"	Bug	closed	Testing framework	dev	Normal	fixed		Matthijs Kooijman	Ready for checkin	1	0	0	0	0	0
