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

Lack of compatibility with Django's unit testing framework #51

Open
Greem666 opened this issue May 7, 2020 · 0 comments
Open

Lack of compatibility with Django's unit testing framework #51

Greem666 opened this issue May 7, 2020 · 0 comments

Comments

@Greem666
Copy link

Greem666 commented May 7, 2020

Hi,

I have a project with the following database setup:

DATABASES = {
    'default': {
        'ENGINE': 'django.db.backends.postgresql',
        'NAME': global_config['db']['database'],
        'USER': global_config['db']['user'],
        'PASSWORD': global_config.get('db', 'password'),
        'HOST': global_config['db']['host'],
        'PORT': global_config['db']['port'],
        'CONN_MAX_AGE': 30,
        'TEST': {
            'NAME': 'mytestdatabase',
        },
        'OPTIONS': {
            'connect_timeout': 60,
            'sslmode': 'prefer'
        },
    },
    'read_replica': {
        'ENGINE': 'django.db.backends.postgresql',
        'NAME': global_config['db']['database_read_replica'],
        'USER': global_config['db']['user_read_replica'],
        'PASSWORD': global_config.get('db', 'password_read_replica'),
        'HOST': global_config['db']['host_read_replica'],
        'PORT': global_config['db']['port_read_replica'],
        'CONN_MAX_AGE': 30,
        'TEST': {
            'MIRROR': 'default',
        },
        'OPTIONS': {
            'connect_timeout': 60,
            'sslmode': 'prefer'
        },
    },
}

REPLICA_DATABASES = ['read_replica',]
DATABASE_ROUTERS = [
    'multidb.PinningReplicaRouter',
    ]
MULTIDB_PINNING_SECONDS = global_config['postgresql'].getint('master_db_pinning_seconds')

When using the following TestSuite code, I get incorrect routing, and read/write operations are not correctly carried out on on the test 'mytestdatabase' specified in default DB's TEST settings. Instead:

  • write operations seem to be done fine (I cannot verify it via pgadmin, since the data is destroyed after every test is complete), but
  • read is done on the PRODUCTION DB
from django.test import TestCase

from DM.tests.factories.UserFactory import UserFactory
from DM.tests.factories.CaseFactory import CaseFactory

from users.models import User
from data.models import Case

import factory

class DATestSuite(TestCase):

    databases = {
        'default', 
        'read_replica',
    }
    
    @classmethod
    def setUpTestData(cls):
        cls.users = UserFactory.create_batch(50)
        cls.cases = CaseFactory.create_batch(50)

    def test_firstOne(self):
        print(Case.objects.all())
        print(User.objects.all())
        self.assertQuerysetEqual(qs=Case.objects.all(), values=DATestSuite.cases, transform = lambda _: _)
import factory
from faker import Factory
import pytz

from DM.tests.factories.AuthGroupFactory import AuthGroupFactory

from users.models import User

faker = Factory.create()

class UserFactory(factory.DjangoModelFactory):
    class Meta:
        model = User
        django_get_or_create = ('first_name', 'last_name', 'timezone', 'locale')
        database = 'default'

    first_name = factory.LazyAttribute(lambda _: faker.first_name())
    last_name = factory.LazyAttribute(lambda _: faker.last_name())
    display_name = factory.LazyAttribute(lambda _: _.first_name + " " + _.last_name)    
    timezone = factory.LazyAttribute(lambda _: faker.timezone())
    locale = factory.LazyAttribute(lambda _: faker.random_choices(elements=('en-au', 'en-us', 'de-de', 'fr-fr'), length=1))
    password = factory.LazyAttribute(lambda _: faker.password(length=12))
    last_login = factory.LazyAttribute(lambda _: faker.past_datetime(start_date="-60d", tzinfo=pytz.timezone(faker.timezone())))
    is_superuser = factory.LazyAttribute(lambda _: faker.boolean(50))
    email = factory.LazyAttribute(lambda _: faker.email())
    username = factory.LazyAttribute(lambda _: _.email)
    is_staff = factory.LazyAttribute(lambda _: faker.boolean(50))
    is_active = factory.LazyAttribute(lambda _: faker.boolean(50))
    date_joined = factory.LazyAttribute(lambda _: faker.past_datetime(start_date="-1y", tzinfo=pytz.timezone(faker.timezone())))
    groups = factory.RelatedFactory(AuthGroupFactory)
import factory
from faker import Factory
import pytz

from DM.tests.factories.UserFactory import UserFactory

from data.models import Case
from users.models import User

faker = Factory.create()

class CaseFactory(factory.DjangoModelFactory):
    class Meta:
        model = Case
        database = 'default'

    user = factory.Iterator(User.objects.all())
    uploaded_on = factory.LazyAttribute(lambda _: faker.date_time(tzinfo=pytz.timezone(faker.timezone())))
    uuid_hex = factory.LazyAttribute(lambda _: faker.hexify(text="^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^"))
    upload_country = factory.LazyAttribute(lambda _: faker.country_code())
    additional_info = faker.paragraph()
import factory
from faker import Factory

from django.contrib.auth.models import Group

faker = Factory.create()

class AuthGroupFactory(factory.DjangoModelFactory):

    class Meta:
        model = Group
        django_get_or_create = ('name',)
    
    name = factory.Iterator(["default_user", "different_user_1", "different_user_2", "different_user_3"])
    permissions = None

As an effect, it becomes impossible to carry out any DB-based unit tests. I had to manually comment out the 'multidb.PinningReplicaRouter' in DATABASE_ROUTERS for Django's test suite to start working as intended.

Is that a known issue, and if so - are there any neat workarounds, or plans to have it fixed?

Here are my dependencies captured in requirements.txt:

Django==2.2.11
watchtower==0.7.3
boto3==1.12.13
django-debug-toolbar==2.2
django-ipware==2.1.0
taggit-selectize==2.7.1
django-taggit==1.2.0
django-braces==1.14.0
psycopg2-binary==2.8.4
pycryptodome==3.9.4
XlsxWriter==1.2.8
xlrd==1.2.0
openpyxl==3.0.3
unidecode==1.1.1
django-background-tasks==1.2.5
django-multidb-router==0.9
matplotlib==3.1.2
django-constance[database]==2.6.0
cx-Oracle==7.3.0
pandas==1.0.1
croniter==0.3.31
ipython==7.13.0
djangorestframework==3.11.0
django-cors-headers==3.2.1
dateparser==0.7.2
requests==2.23.0
Faker==4.0.3
factory_boy==2.12.0
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

1 participant