Opened 8 years ago

Closed 8 years ago

#27286 closed Bug (duplicate)

Tests fail on MySQL when using multi-db and some DB is read-only due to supports_transactions() call

Reported by: Jose M Herrero Owned by: Mariusz Felisiak
Component: Testing framework Version: 1.10
Severity: Normal Keywords: multi-db dbrouter
Cc: Triage Stage: Unreviewed
Has patch: no Needs documentation: no
Needs tests: no Patch needs improvement: no
Easy pickings: no UI/UX: no

Description

I'm triying to implement a multi-db platform with one master and some read-replicas, I wanted to reflect this structure also in tests. When I run tests they try to write to read only databases although router is configured to not allow it.
To reproduce with nothing interfering I started a fresh project, these are the steps to reproduce:

  1. Start a new Django 1.10.1 project with django-admin startproject mysite and cd into it cd mysite
  2. Create a database router mysite/dbrouter.py

    Code highlighting:

    class DbRouter(object):
        def db_for_read(self, model, **hints):
            return 'read_replica'
    
        def db_for_write(self, model, **hints):
            return 'default'
    
        def allow_relation(self, obj1, obj2, **hints):
            return True
    
        def allow_migrate(self, db, app_label, model_name=None, **hints):
            if db == 'read_replica':
                return False
            return True
    
  1. Edit mysite.settings.py with master and read databases and set the database router

Code highlighting:

DATABASES = {
    'default': {
        'ENGINE': 'django.db.backends.mysql',
        'NAME': 'mysite',
        'USER': 'myuser',
        'PASSWORD': 'mypassword',
        'HOST': '127.0.0.1',
        'PORT': '',
    },
    'read_replica': {
        'ENGINE': 'django.db.backends.mysql',
        'NAME': 'mysite',
        'USER': 'myuser_read',
        'PASSWORD': 'myreadpassword',
        'HOST': '127.0.0.1',
        'PORT': '',
    },
}
DATABASE_ROUTERS = ['mysite.dbrouter.DbRouter']
  1. Create mysite/tests.py

    Code highlighting:

    from django.test import TestCase
    
    class SurveyFormTest(TestCase):
        def test_sample(self):
            print 'hello'
    
  2. Execute the tests and bang! python manage.py test mysite
Creating test database for alias 'default'...
E
======================================================================
ERROR: setUpClass (mysite.tests.SurveyFormTest)
----------------------------------------------------------------------
Traceback (most recent call last):
  File "/home/chemary/workspace/myvirtualenv/local/lib/python2.7/site-packages/django/test/testcases.py", line 1009, in setUpClass
    if not connections_support_transactions():
  File "/home/chemary/workspace/myvirtualenv/local/lib/python2.7/site-packages/django/test/testcases.py", line 974, in connections_support_transactions
    for conn in connections.all())
  File "/home/chemary/workspace/myvirtualenv/local/lib/python2.7/site-packages/django/test/testcases.py", line 974, in <genexpr>
    for conn in connections.all())
  File "/home/chemary/workspace/myvirtualenv/local/lib/python2.7/site-packages/django/utils/functional.py", line 35, in __get__
    res = instance.__dict__[self.name] = self.func(instance)
  File "/home/chemary/workspace/myvirtualenv/local/lib/python2.7/site-packages/django/db/backends/base/features.py", line 235, in supports_transactions
    cursor.execute('CREATE TABLE ROLLBACK_TEST (X INT)')
  File "/home/chemary/workspace/myvirtualenv/local/lib/python2.7/site-packages/django/db/backends/utils.py", line 64, in execute
    return self.cursor.execute(sql, params)
  File "/home/chemary/workspace/myvirtualenv/local/lib/python2.7/site-packages/django/db/utils.py", line 94, in __exit__
    six.reraise(dj_exc_type, dj_exc_value, traceback)
  File "/home/chemary/workspace/myvirtualenv/local/lib/python2.7/site-packages/django/db/backends/utils.py", line 62, in execute
    return self.cursor.execute(sql)
  File "/home/chemary/workspace/myvirtualenv/local/lib/python2.7/site-packages/django/db/backends/mysql/base.py", line 112, in execute
    return self.cursor.execute(query, args)
  File "/home/chemary/workspace/myvirtualenv/local/lib/python2.7/site-packages/MySQLdb/cursors.py", line 205, in execute
    self.errorhandler(self, exc, value)
  File "/home/chemary/workspace/myvirtualenv/local/lib/python2.7/site-packages/MySQLdb/connections.py", line 36, in defaulterrorhandler
    raise errorclass, errorvalue
OperationalError: (1142, "CREATE command denied to user 'myuser_read'@'localhost' for table 'ROLLBACK_TEST'")

----------------------------------------------------------------------
Ran 0 tests in 0.026s

FAILED (errors=1)
Destroying test database for alias 'default'...

Change History (5)

comment:1 by Jose M Herrero, 8 years ago

I have tried to add configuration mentioned here but the error is the same
https://docs.djangoproject.com/en/1.10/topics/testing/advanced/#tests-and-multiple-databases

comment:2 by Tim Graham, 8 years ago

Do you have any ideas about how we could detect whether or not the database supports transactions besides the current algorithm that requires creating a table?

in reply to:  2 comment:3 by Mariusz Felisiak, 8 years ago

Owner: changed from nobody to Mariusz Felisiak
Status: newassigned

comment:4 by Mariusz Felisiak, 8 years ago

New algorithm for mySQL that determines whether the database supports transactions, instead of CREATE TABLE... test PR

comment:5 by Tim Graham, 8 years ago

Resolution: duplicate
Status: assignedclosed
Summary: Tests fails when using multi-db and some DB is read-onlyTests fail on MySQL when using multi-db and some DB is read-only due to supports_transactions() call

Duplicate of #26541

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