Refactored tests and added tests checking syncing TENANT_APPS and SHARED_APPS behavior.
This commit is contained in:
parent
1e6bd4028c
commit
70dd4ad463
|
@ -0,0 +1,12 @@
|
|||
from django.db import models
|
||||
|
||||
|
||||
class DummyModel(models.Model):
|
||||
"""
|
||||
Just a test model so we can test manipulating data
|
||||
inside a tenant
|
||||
"""
|
||||
name = models.CharField(max_length=100)
|
||||
|
||||
def __unicode__(self):
|
||||
return self.name
|
|
@ -6,7 +6,7 @@ from tenant_schemas.utils import get_tenant_model
|
|||
class TenantTestCase(TestCase):
|
||||
@classmethod
|
||||
def setUpClass(cls):
|
||||
# create a tenant
|
||||
cls.sync_shared()
|
||||
tenant_domain = 'tenant.test.com'
|
||||
cls.tenant = get_tenant_model()(domain_url=tenant_domain, schema_name='test')
|
||||
cls.tenant.save(verbosity=0) # todo: is there any way to get the verbosity from the test command here?
|
||||
|
@ -15,7 +15,6 @@ class TenantTestCase(TestCase):
|
|||
|
||||
@classmethod
|
||||
def tearDownClass(cls):
|
||||
# delete tenant
|
||||
connection.set_schema_to_public()
|
||||
cls.tenant.delete()
|
||||
|
||||
|
|
|
@ -13,19 +13,5 @@ class Tenant(TenantMixin):
|
|||
class NonAutoSyncTenant(TenantMixin):
|
||||
auto_create_schema = False
|
||||
|
||||
class Meta:
|
||||
app_label = 'tenant_schemas'
|
||||
|
||||
|
||||
class DummyModel(models.Model):
|
||||
"""
|
||||
Just a test model so we can test manipulating data
|
||||
inside a tenant
|
||||
"""
|
||||
name = models.CharField(max_length=1337) # every dummy should have a pretty name :)
|
||||
|
||||
def __unicode__(self):
|
||||
return self.name
|
||||
|
||||
class Meta:
|
||||
app_label = 'tenant_schemas'
|
|
@ -1,4 +1,6 @@
|
|||
from django.conf import settings
|
||||
from django.test.client import RequestFactory
|
||||
from tenant_schemas import get_public_schema_name
|
||||
|
||||
from tenant_schemas.middleware import TenantMiddleware
|
||||
from tenant_schemas.tests.models import Tenant
|
||||
|
@ -6,6 +8,18 @@ from tenant_schemas.tests.testcases import BaseTestCase
|
|||
|
||||
|
||||
class RoutesTestCase(BaseTestCase):
|
||||
@classmethod
|
||||
def setUpClass(cls):
|
||||
super(RoutesTestCase, cls).setUpClass()
|
||||
settings.SHARED_APPS = ('tenant_schemas', )
|
||||
settings.TENANT_APPS = ('dts_test_app',
|
||||
'django.contrib.contenttypes',
|
||||
'django.contrib.auth', )
|
||||
settings.INSTALLED_APPS = settings.SHARED_APPS + settings.TENANT_APPS
|
||||
cls.sync_shared()
|
||||
cls.public_tenant = Tenant(domain_url='test.com', schema_name=get_public_schema_name())
|
||||
cls.public_tenant.save()
|
||||
|
||||
def setUp(self):
|
||||
super(RoutesTestCase, self).setUp()
|
||||
self.factory = RequestFactory()
|
||||
|
@ -17,7 +31,7 @@ class RoutesTestCase(BaseTestCase):
|
|||
|
||||
def test_tenant_routing(self):
|
||||
"""
|
||||
request path should not be altered
|
||||
Request path should not be altered.
|
||||
"""
|
||||
request_url = '/any/request/'
|
||||
request = self.factory.get('/any/request/',
|
||||
|
@ -31,11 +45,11 @@ class RoutesTestCase(BaseTestCase):
|
|||
|
||||
def test_public_schema_routing(self):
|
||||
"""
|
||||
request path should not be altered
|
||||
Request path should not be altered.
|
||||
"""
|
||||
request_url = '/any/request/'
|
||||
request = self.factory.get('/any/request/',
|
||||
HTTP_HOST=self.public_tenant_domain)
|
||||
HTTP_HOST=self.public_tenant.domain_url)
|
||||
self.tm.process_request(request)
|
||||
|
||||
self.assertEquals(request.path_info, request_url)
|
||||
|
|
|
@ -1,19 +1,33 @@
|
|||
from django.conf import settings
|
||||
from django.db import connection
|
||||
|
||||
from tenant_schemas.tests.models import Tenant, NonAutoSyncTenant, DummyModel
|
||||
from tenant_schemas.tests.testcases import BaseTestCase
|
||||
from tenant_schemas.utils import tenant_context, schema_context, schema_exists, get_tenant_model
|
||||
from dts_test_app.models import DummyModel
|
||||
from tenant_schemas.test.cases import TenantTestCase
|
||||
from tenant_schemas.tests.models import Tenant, NonAutoSyncTenant
|
||||
from tenant_schemas.tests.testcases import BaseTestCase
|
||||
from tenant_schemas.utils import tenant_context, schema_context, schema_exists, get_tenant_model, get_public_schema_name
|
||||
|
||||
class TenantTest(BaseTestCase):
|
||||
def tearDown(self):
|
||||
super(TenantTest, self).tearDown()
|
||||
NonAutoSyncTenant.objects.all().delete()
|
||||
|
||||
class TenantDataAndSettingsTest(BaseTestCase):
|
||||
"""
|
||||
Tests if the tenant model settings work properly and if data can be saved
|
||||
and persisted to different tenants.
|
||||
"""
|
||||
|
||||
@classmethod
|
||||
def setUpClass(cls):
|
||||
super(TenantDataAndSettingsTest, cls).setUpClass()
|
||||
settings.SHARED_APPS = ('tenant_schemas', )
|
||||
settings.TENANT_APPS = ('dts_test_app',
|
||||
'django.contrib.contenttypes',
|
||||
'django.contrib.auth', )
|
||||
settings.INSTALLED_APPS = settings.SHARED_APPS + settings.TENANT_APPS
|
||||
cls.sync_shared()
|
||||
Tenant(domain_url='test.com', schema_name=get_public_schema_name()).save()
|
||||
|
||||
def test_tenant_schema_is_created(self):
|
||||
"""
|
||||
when saving a tenant, it's schema should be created
|
||||
When saving a tenant, it's schema should be created.
|
||||
"""
|
||||
tenant = Tenant(domain_url='something.test.com', schema_name='test')
|
||||
tenant.save()
|
||||
|
@ -22,8 +36,8 @@ class TenantTest(BaseTestCase):
|
|||
|
||||
def test_non_auto_sync_tenant(self):
|
||||
"""
|
||||
when saving a tenant that has the flag auto_create_schema as
|
||||
False, the schema should not be created when saving the tenant
|
||||
When saving a tenant that has the flag auto_create_schema as
|
||||
False, the schema should not be created when saving the tenant.
|
||||
"""
|
||||
self.assertFalse(schema_exists('non_auto_sync_tenant'))
|
||||
|
||||
|
@ -35,7 +49,7 @@ class TenantTest(BaseTestCase):
|
|||
|
||||
def test_sync_tenant(self):
|
||||
"""
|
||||
when editing an existing tenant, all data should be kept
|
||||
When editing an existing tenant, all data should be kept.
|
||||
"""
|
||||
tenant = Tenant(domain_url='something.test.com', schema_name='test')
|
||||
tenant.save()
|
||||
|
@ -58,8 +72,6 @@ class TenantTest(BaseTestCase):
|
|||
self.assertEquals(DummyModel.objects.count(), 2)
|
||||
|
||||
def test_switching_search_path(self):
|
||||
dummies_tenant1_count, dummies_tenant2_count = 0, 0
|
||||
|
||||
tenant1 = Tenant(domain_url='something.test.com',
|
||||
schema_name='tenant1')
|
||||
tenant1.save()
|
||||
|
@ -71,25 +83,23 @@ class TenantTest(BaseTestCase):
|
|||
# go to tenant1's path
|
||||
connection.set_tenant(tenant1)
|
||||
|
||||
# add some data
|
||||
# add some data, 2 DummyModels for tenant1
|
||||
DummyModel(name="Schemas are").save()
|
||||
DummyModel(name="awesome!").save()
|
||||
dummies_tenant1_count = DummyModel.objects.count()
|
||||
|
||||
# switch temporarily to tenant2's path
|
||||
with tenant_context(tenant2):
|
||||
# add some data
|
||||
# add some data, 3 DummyModels for tenant2
|
||||
DummyModel(name="Man,").save()
|
||||
DummyModel(name="testing").save()
|
||||
DummyModel(name="is great!").save()
|
||||
dummies_tenant2_count = DummyModel.objects.count()
|
||||
|
||||
# we should be back to tenant1's path, test what we have
|
||||
self.assertEqual(DummyModel.objects.count(), dummies_tenant1_count)
|
||||
self.assertEqual(2, DummyModel.objects.count())
|
||||
|
||||
# switch back to tenant2's path
|
||||
with tenant_context(tenant2):
|
||||
self.assertEqual(DummyModel.objects.count(), dummies_tenant2_count)
|
||||
self.assertEqual(3, DummyModel.objects.count())
|
||||
|
||||
def test_switching_tenant_without_previous_tenant(self):
|
||||
tenant = Tenant(domain_url='something.test.com', schema_name='test')
|
||||
|
@ -104,10 +114,99 @@ class TenantTest(BaseTestCase):
|
|||
DummyModel(name="Survived it!").save()
|
||||
|
||||
|
||||
class TenantSyncTest(BaseTestCase):
|
||||
"""
|
||||
Tests if the shared apps and the tenant apps get synced correctly
|
||||
depending on if the public schema or a tenant is being synced.
|
||||
"""
|
||||
|
||||
def test_shared_apps_does_not_sync_tenant_apps(self):
|
||||
"""
|
||||
Tests that if an app is in SHARED_APPS, it does not get synced to
|
||||
the a tenant schema.
|
||||
"""
|
||||
settings.SHARED_APPS = ('tenant_schemas', # 2 tables
|
||||
'django.contrib.auth', # 6 tables
|
||||
'django.contrib.contenttypes', ) # 1 table
|
||||
settings.TENANT_APPS = ('django.contrib.sessions', )
|
||||
settings.INSTALLED_APPS = settings.SHARED_APPS + settings.TENANT_APPS
|
||||
self.sync_shared()
|
||||
|
||||
shared_tables = self.get_tables_list_in_schema(get_public_schema_name())
|
||||
self.assertEqual(2+6+1, len(shared_tables))
|
||||
self.assertNotIn('django_session', shared_tables)
|
||||
|
||||
def test_tenant_apps_does_not_sync_shared_apps(self):
|
||||
"""
|
||||
Tests that if an app is in TENANT_APPS, it does not get synced to
|
||||
the public schema.
|
||||
"""
|
||||
settings.SHARED_APPS = ('tenant_schemas',
|
||||
'django.contrib.auth',
|
||||
'django.contrib.contenttypes', )
|
||||
settings.TENANT_APPS = ('django.contrib.sessions', ) # 1 table
|
||||
settings.INSTALLED_APPS = settings.SHARED_APPS + settings.TENANT_APPS
|
||||
self.sync_shared()
|
||||
tenant = Tenant(domain_url='arbitrary.test.com', schema_name='test')
|
||||
tenant.save()
|
||||
|
||||
tenant_tables = self.get_tables_list_in_schema(tenant.schema_name)
|
||||
self.assertEqual(1, len(tenant_tables))
|
||||
self.assertIn('django_session', tenant_tables)
|
||||
|
||||
def test_tenant_apps_and_shared_apps_can_have_the_same_apps(self):
|
||||
"""
|
||||
Tests that both SHARED_APPS and TENANT_APPS can have apps in common.
|
||||
In this case they should get synced to both tenant and public schemas.
|
||||
"""
|
||||
settings.SHARED_APPS = ('tenant_schemas', # 2 tables
|
||||
'django.contrib.auth', # 6 tables
|
||||
'django.contrib.contenttypes', # 1 table
|
||||
'django.contrib.sessions', ) # 1 table
|
||||
settings.TENANT_APPS = ('django.contrib.sessions', ) # 1 table
|
||||
settings.INSTALLED_APPS = settings.SHARED_APPS + settings.TENANT_APPS
|
||||
self.sync_shared()
|
||||
tenant = Tenant(domain_url='arbitrary.test.com', schema_name='test')
|
||||
tenant.save()
|
||||
|
||||
shared_tables = self.get_tables_list_in_schema(get_public_schema_name())
|
||||
tenant_tables = self.get_tables_list_in_schema(tenant.schema_name)
|
||||
self.assertEqual(2+6+1+1, len(shared_tables))
|
||||
self.assertIn('django_session', tenant_tables)
|
||||
self.assertEqual(1, len(tenant_tables))
|
||||
self.assertIn('django_session', tenant_tables)
|
||||
|
||||
def test_content_types_is_not_mandatory(self):
|
||||
"""
|
||||
Tests that even if content types is in SHARED_APPS, it's
|
||||
not required in TENANT_APPS.
|
||||
"""
|
||||
settings.SHARED_APPS = ('tenant_schemas', # 2 tables
|
||||
'django.contrib.contenttypes', ) # 1 table
|
||||
settings.TENANT_APPS = ('django.contrib.sessions', ) # 1 table
|
||||
settings.INSTALLED_APPS = settings.SHARED_APPS + settings.TENANT_APPS
|
||||
self.sync_shared()
|
||||
tenant = Tenant(domain_url='something.test.com', schema_name='test')
|
||||
tenant.save()
|
||||
|
||||
shared_tables = self.get_tables_list_in_schema(get_public_schema_name())
|
||||
tenant_tables = self.get_tables_list_in_schema(tenant.schema_name)
|
||||
self.assertEqual(2+1, len(shared_tables))
|
||||
self.assertIn('django_session', tenant_tables)
|
||||
self.assertEqual(1, len(tenant_tables))
|
||||
self.assertIn('django_session', tenant_tables)
|
||||
|
||||
|
||||
class TenantTestCaseTest(BaseTestCase, TenantTestCase):
|
||||
"""
|
||||
Tests that the tenant created inside TenantTestCase persists on
|
||||
all functions.
|
||||
"""
|
||||
|
||||
def test_tenant_survives_after_method1(self):
|
||||
# There are two tenants (public plus the one created by TenantTestCase)
|
||||
self.assertEquals(1 + 1, get_tenant_model().objects.all().count())
|
||||
# There is one tenant in the database, the one created by TenantTestCase
|
||||
self.assertEquals(1, get_tenant_model().objects.all().count())
|
||||
|
||||
def test_tenant_survives_after_method2(self):
|
||||
self.assertEquals(1 + 1, get_tenant_model().objects.all().count())
|
||||
# The same tenant still exists even after the previous method call
|
||||
self.assertEquals(1, get_tenant_model().objects.all().count())
|
||||
|
|
|
@ -1,51 +1,52 @@
|
|||
from django.conf import settings
|
||||
from django.core.management import call_command
|
||||
from django.db import connection
|
||||
from django.test import TransactionTestCase
|
||||
from django.test import TestCase
|
||||
|
||||
from .models import Tenant
|
||||
from ..utils import get_public_schema_name
|
||||
from tenant_schemas.utils import get_public_schema_name
|
||||
|
||||
|
||||
class BaseTestCase(TransactionTestCase):
|
||||
""" Base test case that comes packed with overloaded INSTALLED_APPS,
|
||||
custom public tenant, and schemas cleanup on tearDown.
|
||||
class BaseTestCase(TestCase):
|
||||
"""
|
||||
Base test case that comes packed with overloaded INSTALLED_APPS,
|
||||
custom public tenant, and schemas cleanup on tearDown.
|
||||
"""
|
||||
@classmethod
|
||||
def setUpClass(cls):
|
||||
# settings needs some patching
|
||||
settings.TENANT_MODEL = 'tenant_schemas.Tenant'
|
||||
settings.TENANT_APPS = ('tenant_schemas',
|
||||
settings.SHARED_APPS = ('tenant_schemas', )
|
||||
settings.TENANT_APPS = ('dts_test_app',
|
||||
'django.contrib.contenttypes',
|
||||
'django.contrib.auth', )
|
||||
settings.INSTALLED_APPS = settings.SHARED_APPS + settings.TENANT_APPS
|
||||
|
||||
# Django calls syncdb by default for the test database, but we want
|
||||
# a blank public schema for this set of tests.
|
||||
connection.set_schema_to_public()
|
||||
cursor = connection.cursor()
|
||||
cursor.execute('DROP SCHEMA %s CASCADE; CREATE SCHEMA %s;'
|
||||
% (get_public_schema_name(), get_public_schema_name(), ))
|
||||
super(BaseTestCase, cls).setUpClass()
|
||||
|
||||
def setUp(self):
|
||||
connection.set_schema_to_public()
|
||||
super(BaseTestCase, self).setUp()
|
||||
|
||||
# add the public tenant
|
||||
self.public_tenant_domain = 'test.com'
|
||||
self.public_tenant = Tenant(domain_url=self.public_tenant_domain,
|
||||
schema_name='public')
|
||||
self.public_tenant.save()
|
||||
|
||||
connection.set_schema_to_public()
|
||||
|
||||
def tearDown(self):
|
||||
"""
|
||||
Delete all tenant schemas. Tenant schema are not deleted
|
||||
automatically by django.
|
||||
"""
|
||||
connection.set_schema_to_public()
|
||||
do_not_delete = [get_public_schema_name(), 'information_schema']
|
||||
@classmethod
|
||||
def get_tables_list_in_schema(cls, schema_name):
|
||||
cursor = connection.cursor()
|
||||
sql = """SELECT table_name FROM information_schema.tables
|
||||
WHERE table_schema = %s"""
|
||||
cursor.execute(sql, (schema_name, ))
|
||||
return [row[0] for row in cursor.fetchall()]
|
||||
|
||||
# Use information_schema.schemata instead of pg_catalog.pg_namespace in
|
||||
# utils.schema_exists, so that we only "see" schemas that we own
|
||||
cursor.execute('SELECT schema_name FROM information_schema.schemata')
|
||||
|
||||
for row in cursor.fetchall():
|
||||
if not row[0].startswith('pg_') and row[0] not in do_not_delete:
|
||||
print("Deleting schema %s" % row[0])
|
||||
cursor.execute('DROP SCHEMA %s CASCADE' % row[0])
|
||||
|
||||
Tenant.objects.all().delete()
|
||||
@classmethod
|
||||
def sync_shared(cls):
|
||||
call_command('sync_schemas',
|
||||
schema_name=get_public_schema_name(),
|
||||
tenant=False,
|
||||
public=True,
|
||||
interactive=False,
|
||||
migrate_all=True,
|
||||
verbosity=0,
|
||||
)
|
Loading…
Reference in New Issue