Opened 14 years ago

Last modified 13 years ago

#16088 closed Bug

Multi-database tests fail in ContentType — at Version 6

Reported by: def@… Owned by: nobody
Component: Database layer (models, ORM) Version: 1.2
Severity: Normal Keywords: ContentType
Cc: Triage Stage: Unreviewed
Has patch: yes Needs documentation: no
Needs tests: no Patch needs improvement: no
Easy pickings: no UI/UX: no

Description (last modified by Łukasz Rekucki)

I have a multi-database setup:

DATABASES = {
    'default': {
        'ENGINE': 'django.db.backends.mysql',
        'NAME': 'wall2',
        'HOST': 'localhost',
        'PORT': '',
    },

    'slave': {
        'ENGINE': 'django.db.backends.mysql',
        'NAME': 'wall2',
        'HOST': 'localhost',
        'PORT': '',
        'TEST_MIRROR': 'default',
    },

    'station': {
        'ENGINE': 'django.db.backends.mysql',
        'NAME': 'station',
        'HOST': 'localhost',
        'PORT': '',
        'TEST_DEPENDENCIES': ['default',]
    },

    'catalog': {
        'ENGINE': 'django.db.backends.mysql',
        'NAME': 'catalog',
        'HOST': 'localhost',
        'PORT': '',
        'TEST_DEPENDENCIES': ['default', 'station']
    },
}

I have 2 routers, one handles the master/slave and one handles the 2 "data" database station and catalog. they run fine on production, but when we try to run our unit tests i get the following stack trace:

Traceback (most recent call last):
  File "./27.py", line 11, in <module>
    execute_manager(settings)
  File "/usr/lib/python2.7/site-packages/django/core/management/__init__.py", line 438, in execute_manager
    utility.execute()
  File "/usr/lib/python2.7/site-packages/django/core/management/__init__.py", line 379, in execute
    self.fetch_command(subcommand).run_from_argv(self.argv)
  File "/usr/lib/python2.7/site-packages/django/core/management/base.py", line 191, in run_from_argv
    self.execute(*args, **options.__dict__)
  File "/usr/lib/python2.7/site-packages/django/core/management/base.py", line 220, in execute
    output = self.handle(*args, **options)
  File "/usr/lib/python2.7/site-packages/south/management/commands/test.py", line 8, in handle
    super(Command, self).handle(*args, **kwargs)
  File "/usr/lib/python2.7/site-packages/django/core/management/commands/test.py", line 37, in handle
    failures = test_runner.run_tests(test_labels)
  File "/usr/lib/python2.7/site-packages/django/test/simple.py", line 396, in run_tests
    old_config = self.setup_databases()
  File "/usr/lib/python2.7/site-packages/django/test/simple.py", line 334, in setup_databases
    test_db_name = connection.creation.create_test_db(self.verbosity, autoclobber=not self.interactive)
  File "/usr/lib/python2.7/site-packages/django/db/backends/creation.py", line 357, in create_test_db
    load_initial_data=False)
  File "/usr/lib/python2.7/site-packages/django/core/management/__init__.py", line 166, in call_command
    return klass.execute(*args, **defaults)
  File "/usr/lib/python2.7/site-packages/django/core/management/base.py", line 220, in execute
    output = self.handle(*args, **options)
  File "/usr/lib/python2.7/site-packages/django/core/management/base.py", line 351, in handle
    return self.handle_noargs(**options)
  File "/usr/lib/python2.7/site-packages/django/core/management/commands/syncdb.py", line 107, in handle_noargs
    emit_post_sync_signal(created_models, verbosity, interactive, db)
  File "/usr/lib/python2.7/site-packages/django/core/management/sql.py", line 182, in emit_post_sync_signal
    interactive=interactive, db=db)
  File "/usr/lib/python2.7/site-packages/django/dispatch/dispatcher.py", line 172, in send
    response = receiver(signal=self, sender=sender, **named)
  File "/usr/lib/python2.7/site-packages/django/contrib/contenttypes/management.py", line 25, in update_contenttypes
    ct.save()
  File "/usr/lib/python2.7/site-packages/django/db/models/base.py", line 458, in save
    self.save_base(using=using, force_insert=force_insert, force_update=force_update)
  File "/usr/lib/python2.7/site-packages/django/db/models/base.py", line 551, in save_base
    result = manager._insert(values, return_id=update_pk, using=using)
  File "/usr/lib/python2.7/site-packages/django/db/models/manager.py", line 195, in _insert
    return insert_query(self.model, values, **kwargs)
  File "/usr/lib/python2.7/site-packages/django/db/models/query.py", line 1524, in insert_query
    return query.get_compiler(using=using).execute_sql(return_id)
  File "/usr/lib/python2.7/site-packages/django/db/models/sql/compiler.py", line 788, in execute_sql
    cursor = super(SQLInsertCompiler, self).execute_sql(None)
  File "/usr/lib/python2.7/site-packages/django/db/models/sql/compiler.py", line 732, in execute_sql
    cursor.execute(sql, params)
  File "/usr/lib/python2.7/site-packages/django/db/backends/mysql/base.py", line 86, in execute
    return self.cursor.execute(query, args)
  File "/usr/lib64/python2.7/site-packages/MySQLdb/cursors.py", line 174, in execute
    self.errorhandler(self, exc, value)
  File "/usr/lib64/python2.7/site-packages/MySQLdb/connections.py", line 36, in defaulterrorhandler
    raise errorclass, errorvalue
django.db.utils.IntegrityError: (1062, "Duplicate entry 'tools-station' for key 'app_label'")

after some debugging i've found that the

    def update_contenttypes(app, created_models, verbosity=2, **kwargs):

method looks up the tools-station content type in the station database, doesn't find it, and then tries to write it to the default database, where it already exists.

by simply adding "using('default')" to the two ContentType.objects calls in the above method everything works fine. i'm not sure if all content types are meant to be in the 'default' database, but that seems to be the only way it can work at this point?

i'll attach a simple patch,

Change History (9)

by anonymous, 14 years ago

Attachment: management.diff added

comment:1 by Aymeric Augustin, 14 years ago

Resolution: needsinfo
Status: newclosed

Either your database routers allow reading ContentType objects in the 'station' database (which they shouldn't), or they are bypassed somehow.

Could you post the code of your routers?

comment:2 by Aymeric Augustin, 14 years ago

And, obviously, re-open the ticket - thanks :)

by def@…, 13 years ago

Attachment: dbutil.py added

db router

comment:3 by anonymous, 13 years ago

Resolution: needsinfo
Status: closedreopened

by def@…, 13 years ago

Attachment: db.py added

last router in chain

comment:4 by def@…, 13 years ago

UI/UX: unset

i have added a test for ContentType and the first router returns 'None' and the final router returns slave on calls to db_for_read for ContentType.

comment:5 by Bas Peschier, 13 years ago

Seems like this is not the only ticket about multi-db contenttype problems, could you test whether ticket #16281 solves your problem?

comment:6 by Łukasz Rekucki, 13 years ago

Description: modified (diff)

Fixed formatting (please use preview!).

Note: See TracTickets for help on using tickets.
Back to Top