Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

django_db_block access wrong database bug #884

Open
lieric7766 opened this issue Oct 16, 2020 · 2 comments
Open

django_db_block access wrong database bug #884

lieric7766 opened this issue Oct 16, 2020 · 2 comments

Comments

@lieric7766
Copy link

lieric7766 commented Oct 16, 2020

when i tried this command pytest -s --import-mode=importlib it works fine.
but when i tried this pytest -s --import-mode=importlib app/tests/test_filename.py
first time was a general fail output but after that i got this error:

===================================================================================== ERRORS =====================================================================================
_________________________________________________________________ ERROR at setup of test_endpoint_containerList __________________________________________________________________
                                                                                                                                                                                  
self = <django.db.backends.utils.CursorWrapper object at 0x107070190>
sql = 'INSERT INTO "auth_user" ("password", "last_login", "is_superuser", "username", "first_name", "last_name", "email", "is_staff", "is_active", "date_joined") VALUES (%s, %s, 
%s, %s, %s, %s, %s, %s, %s, %s) RETURNING "auth_user"."id"'             
params = ('pbkdf2_sha256$180000$UlJQcZHRuts0$jpA8wYudq5I+QdAPXWe6lvqU7V4t3CvADtn4iXpfR64=', None, False, 'test', '', '', ...)
ignored_wrapper_args = (False, {'connection': <django.db.backends.postgresql.base.DatabaseWrapper object at 0x1068fd290>, 'cursor': <django.db.backends.utils.CursorWrapper object
 at 0x107070190>})                                                                                                                                                                
                                                                                         
    def _execute(self, sql, params, *ignored_wrapper_args):                                                                                                                       
        self.db.validate_no_broken_transaction()
        with self.db.wrap_database_errors:                                                                                                                                        
            if params is None:             
                # params default might be backend specific.                                                                                                                       
                return self.cursor.execute(sql)                
            else:                                                                                                                                                                 
>               return self.cursor.execute(sql, params)
E               psycopg2.errors.UniqueViolation: duplicate key value violates unique constraint "auth_user_username_key"
E               DETAIL:  Key (username)=(test) already exists.                                                                                                                                                                                                             
../../.pyenv/versions/3.7.4/envs/dsl/lib/python3.7/site-packages/django/db/backends/utils.py:86: UniqueViolation             
                                                                                                                                                                                  The above exception was the direct cause of the following exception:

django_db_blocker = <pytest_django.plugin._DatabaseBlocker object at 0x105377f90>
                                                                                         
    @pytest.fixture(scope='session')      
    def test_client(django_db_blocker):
        with django_db_blocker.unblock():                                                
>           User.objects.create_user('test', 'test@test.com', 'test123')
                                            
conftest.py:20:

i checked my postgres database test_dbname first and select auth_user this table and it was empty i couldn't find this user i saved. i found it insert to my original database dbname auth_user table. it only occurred when i test specific test file

my conftest.py

@pytest.fixture(scope='session')
def test_client(django_db_blocker):
    with django_db_blocker.unblock():
        User.objects.create_user('test', 'test@test.com', 'test123')
        client = APIClient()
        client.login(username='test', password='test123')

    return client

my project structure

│   conftest.py    
│
└───app_folder
│   │   apps.py
│   │   models.py
│   │   ...
│   └───tests
│       │   test_file1.py
│       │   test_file2.py
@lieric7766 lieric7766 changed the title django_db_block access wrong database django_db_block access wrong database bug Oct 16, 2020
@jefftriplett
Copy link

Running into this too and I was curious if anyone found a workaround for it?

@archmatters
Copy link

archmatters commented Mar 25, 2022

For anyone else encountering this, there seems to be some magic around having a django_db_setup fixture, which probably should be defined in a conftest.py at project root. See https://pytest-django.readthedocs.io/en/latest/database.html#populate-the-database-with-initial-test-data for an example using django_db_setup...

If I have session-scoped fixtures using django_db_blocker.unblock() without a django_db_setup fixture calling unblock() first, I see those other fixtures using unblock() hitting the wrong database as well. But once I add a django_db_setup fixture, everything goes to the test database. Now, to ensure this gets called first, I think you will need every other session scoped fixture wanting database access to request it. And, you will have data persisting in the DB if you don't add teardown to clean it up (or, I suppose, drop the test database after every session).

For example:
conftest.py

import pytest
from myapp.models import User

@pytest.fixture(scope="session")
def django_db_setup(django_db_setup, django_db_blocker):
    """
    Tie to test database, cleanup at the end.
    """
    with django_db_blocker.unblock():
        yield
        User.objects.all().delete()

myapp/tests/fixtures.py

import pytest
from myapp.models import User

@pytest.fixture(scope="session")
def test_user(django_db_setup, django_db_blocker):
    with django_db_blocker.unblock():
        return User.objects.create_user( ... )

And yes, having the django_db_setup fixture request itself seems to be part of the black magic here. I don't understand how this works to ensure the correct database is used, but it works with my project. I hope this becomes simpler and more straightforward with some of the work to resolve #514 !

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

3 participants