#29052: running test command will truncate the data source database at some
condition
---------------------------------------------+------------------------
Reporter: Muse | Owner: nobody
Type: Bug | Status: new
Component: Testing framework | Version: 2.0
Severity: Normal | Keywords:
Triage Stage: Unreviewed | Has patch: 0
Needs documentation: 0 | Needs tests: 0
Patch needs improvement: 0 | Easy pickings: 0
UI/UX: 0 |
---------------------------------------------+------------------------
= Reappear
When your database config look like following code, reader is the same as
default.
"default" is the data source database.
{{{
#!python
DATABASES = {
'default': {
'ENGINE': 'django.db.backends.mysql',
'NAME': 'test',
'USER': 'root',
'PASSWORD': 'xxxx.',
'HOST': "127.0.0.1",
'PORT': '',
"TEST": {
"COLLATION": "utf8_general_ci",
"CHARSET": "utf8",
},
},
'reader': {
'ENGINE': 'django.db.backends.mysql',
'NAME': 'test',
'USER': 'root',
'PASSWORD': 'xxxx.',
'HOST': "127.0.0.1",
'PORT': '',
"TEST": {
"COLLATION": "utf8_general_ci",
"CHARSET": "utf8",
},
}
}
}}}
When I run ./manage.py test, this's a chance that db test will be
truncated, all data will be removed.
My project run under 1.11.2, but I tested on 2.0.1, problem remained.
= Trace
I following the code, when test database created, there's a method at
django/test/testcases.py was called by unittest.
{{{
#!python
def _fixture_teardown(self):
# Allow TRUNCATE ... CASCADE and don't emit the post_migrate
signal
# when flushing only a subset of the apps
for db_name in self._databases_names(include_mirrors=False):
# Flush the database
inhibit_post_migrate = (
self.available_apps is not None or
( # Inhibit the post_migrate signal when using
serialized
# rollback to avoid trying to recreate the serialized
data.
self.serialized_rollback and
hasattr(connections[db_name],
'_test_serialized_contents')
)
)
call_command('flush', verbosity=0, interactive=False,
database=db_name, reset_sequences=False,
allow_cascade=self.available_apps is not None,
inhibit_post_migrate=inhibit_post_migrate)
}}}
Calling command flush, there's my database murderer. When calling flush,
they using db test not using test_test.
I kept tracing, when testing framework start to initialize environment,
there's a function "setup_databases"(django/test/utils.py) called, it used
to create test database.
{{{
#!python
def setup_databases(verbosity, interactive, keepdb=False, debug_sql=False,
parallel=0, **kwargs):
"""
Create the test databases.
"""
test_databases, mirrored_aliases = get_unique_databases_and_mirrors()
old_names = []
for signature, (db_name, aliases) in test_databases.items():
first_alias = None
for alias in aliases:
connection = connections[alias]
old_names.append((connection, db_name, first_alias is None))
# Actually create the database for the first connection
if first_alias is None:
first_alias = alias
connection.creation.create_test_db(
verbosity=verbosity,
autoclobber=not interactive,
keepdb=keepdb,
serialize=connection.settings_dict.get('TEST',
{}).get('SERIALIZE', True),
)
if parallel > 1:
for index in range(parallel):
connection.creation.clone_test_db(
number=index + 1,
verbosity=verbosity,
keepdb=keepdb,
)
# Configure all other connections as mirrors of the first one
else:
connections[alias].creation.set_as_test_mirror(connections[first_alias].settings_dict)
}}}
At my case, aliases looks like {"reader", "default"} or {"default",
"reader"}.
When default was the first one, create_test_db made
connections.get("default") point to test_test.
On the contrary, connections.get("reader") point to test_test. ** But **,
connections.get("default") still point to test.
When choosing which database to flush, if just one database. Just using
default.
{{{
#!python
@classmethod
def _databases_names(cls, include_mirrors=True):
# If the test case has a multi_db=True flag, act on all databases,
# including mirrors or not. Otherwise, just on the default DB.
if getattr(cls, 'multi_db', False):
return [
alias for alias in connections
if include_mirrors or not
connections[alias].settings_dict['TEST']['MIRROR']
]
else:
return [DEFAULT_DB_ALIAS]
}}}
But default still point to test, not test_test, so, all data gone.
--
Ticket URL: <https://code.djangoproject.com/ticket/29052>
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 post to this group, send email to [email protected].
To view this discussion on the web visit
https://groups.google.com/d/msgid/django-updates/051.c18d4415e2535dccd61b9f7004364c0c%40djangoproject.com.
For more options, visit https://groups.google.com/d/optout.