Added test project to enable testing with additional models and apps. This allow us to test different apps in TENANT_APPS AND SHARED_APPS. Added more tests that ensure cross schema foreign keys are possible, although the constraints are not created.

This commit is contained in:
Bernardo Pires 2014-12-29 00:07:45 +01:00
parent 1019e0186c
commit 9a9b8a00df
11 changed files with 236 additions and 13 deletions

View File

@ -7,6 +7,7 @@ include version.py
include VERSION
recursive-include docs *
recursive-include examples *
recursive-include dts_test_project
# exclude all bytecode
global-exclude *.pyo

View File

@ -1,12 +0,0 @@
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

View File

@ -0,0 +1 @@
__author__ = 'bernardo'

View File

@ -0,0 +1,8 @@
from django.db import models
from tenant_schemas.models import TenantMixin
class Client(TenantMixin):
name = models.CharField(max_length=100)
description = models.TextField(max_length=200)
created_on = models.DateField(auto_now_add=True)

View File

@ -0,0 +1,16 @@
from django.contrib.auth.models import User
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
class ModelWithFkToPublicUser(models.Model):
user = models.ForeignKey(User)

View File

@ -0,0 +1,118 @@
"""
Django settings for dts_test_project project.
For more information on this file, see
https://docs.djangoproject.com/en/1.6/topics/settings/
For the full list of settings and their values, see
https://docs.djangoproject.com/en/1.6/ref/settings/
"""
# Build paths inside the project like this: os.path.join(BASE_DIR, ...)
import os
BASE_DIR = os.path.dirname(os.path.dirname(__file__))
# Quick-start development settings - unsuitable for production
# See https://docs.djangoproject.com/en/1.6/howto/deployment/checklist/
# SECURITY WARNING: keep the secret key used in production secret!
SECRET_KEY = 'cl1)b#c&xmm36z3e(quna-vb@ab#&gpjtdjtpyzh!qn%bc^xxn'
# SECURITY WARNING: don't run with debug turned on in production!
DEBUG = True
TEMPLATE_DEBUG = True
ALLOWED_HOSTS = []
# Application definition
SHARED_APPS = (
'tenant_schemas', # mandatory
'customers', # you must list the app where your tenant model resides in
'django.contrib.auth',
'django.contrib.contenttypes',
'django.contrib.sessions',
'django.contrib.messages',
'django.contrib.staticfiles',
)
TENANT_APPS = (
'dts_test_app',
)
TENANT_MODEL = "customers.Client" # app.Model
INSTALLED_APPS = TENANT_APPS + SHARED_APPS + ('tenant_schemas',)
MIDDLEWARE_CLASSES = (
'django.contrib.sessions.middleware.SessionMiddleware',
'django.middleware.common.CommonMiddleware',
'django.middleware.csrf.CsrfViewMiddleware',
'django.contrib.auth.middleware.AuthenticationMiddleware',
'django.contrib.messages.middleware.MessageMiddleware',
'django.middleware.clickjacking.XFrameOptionsMiddleware',
)
ROOT_URLCONF = 'dts_test_project.urls'
WSGI_APPLICATION = 'dts_test_project.wsgi.application'
# Database
# https://docs.djangoproject.com/en/1.6/ref/settings/#databases
DATABASES = {
'default': {
'ENGINE': 'tenant_schemas.postgresql_backend',
'NAME': 'dts_test_project',
'USER': 'postgres',
'PASSWORD': 'root',
'HOST': 'localhost',
'PORT': '',
}
}
DATABASE_ROUTERS = (
'tenant_schemas.routers.TenantSyncRouter',
)
MIDDLEWARE_CLASSES = (
'tenant_tutorial.middleware.TenantTutorialMiddleware',
'django.middleware.common.CommonMiddleware',
'django.contrib.sessions.middleware.SessionMiddleware',
'django.middleware.csrf.CsrfViewMiddleware',
'django.contrib.auth.middleware.AuthenticationMiddleware',
'django.contrib.messages.middleware.MessageMiddleware',
)
TEMPLATE_CONTEXT_PROCESSORS = (
'django.core.context_processors.request',
'django.contrib.auth.context_processors.auth',
'django.core.context_processors.debug',
'django.core.context_processors.media',
'django.core.context_processors.static',
'django.contrib.messages.context_processors.messages',
)
# Internationalization
# https://docs.djangoproject.com/en/1.6/topics/i18n/
LANGUAGE_CODE = 'en-us'
TIME_ZONE = 'UTC'
USE_I18N = True
USE_L10N = True
USE_TZ = True
# Static files (CSS, JavaScript, Images)
# https://docs.djangoproject.com/en/1.6/howto/static-files/
STATIC_URL = '/static/'

10
dts_test_project/manage.py Executable file
View File

@ -0,0 +1,10 @@
#!/usr/bin/env python
import os
import sys
if __name__ == "__main__":
os.environ.setdefault("DJANGO_SETTINGS_MODULE", "dts_test_project.settings")
from django.core.management import execute_from_command_line
execute_from_command_line(sys.argv)

View File

@ -0,0 +1 @@
/home/bernardo/projects/django-tenant-schemas/tenant_schemas

View File

@ -1,7 +1,8 @@
from django.conf import settings
from django.contrib.auth.models import User
from django.db import connection
from dts_test_app.models import DummyModel
from dts_test_app.models import DummyModel, ModelWithFkToPublicUser
from tenant_schemas.test.cases import TenantTestCase
from tenant_schemas.tests.models import Tenant, NonAutoSyncTenant
from tenant_schemas.tests.testcases import BaseTestCase
@ -197,6 +198,85 @@ class TenantSyncTest(BaseTestCase):
self.assertIn('django_session', tenant_tables)
class SharedAuthTest(BaseTestCase):
@classmethod
def setUpClass(cls):
super(SharedAuthTest, cls).setUpClass()
settings.SHARED_APPS = ('tenant_schemas',
'django.contrib.auth',
'django.contrib.contenttypes', )
settings.TENANT_APPS = ('dts_test_app', )
settings.INSTALLED_APPS = settings.SHARED_APPS + settings.TENANT_APPS
cls.sync_shared()
Tenant(domain_url='test.com', schema_name=get_public_schema_name()).save()
# Create a tenant
cls.tenant = Tenant(domain_url='tenant.test.com', schema_name='tenant')
cls.tenant.save()
# Create some users
with schema_context(get_public_schema_name()): # this could actually also be executed inside a tenant
cls.user1 = User(username='arbitrary-1', email="arb1@test.com")
cls.user1.save()
cls.user2 = User(username='arbitrary-2', email="arb2@test.com")
cls.user2.save()
# Create instances on the tenant that point to the users on public
with tenant_context(cls.tenant):
cls.d1 = ModelWithFkToPublicUser(user=cls.user1)
cls.d1.save()
cls.d2 = ModelWithFkToPublicUser(user=cls.user2)
cls.d2.save()
def test_cross_schema_constraint_gets_created(self):
"""
Tests that a foreign key constraint gets created even for cross schema references.
"""
sql = """
SELECT
tc.constraint_name, tc.table_name, kcu.column_name,
ccu.table_name AS foreign_table_name,
ccu.column_name AS foreign_column_name
FROM
information_schema.table_constraints AS tc
JOIN information_schema.key_column_usage AS kcu
ON tc.constraint_name = kcu.constraint_name
JOIN information_schema.constraint_column_usage AS ccu
ON ccu.constraint_name = tc.constraint_name
WHERE constraint_type = 'FOREIGN KEY' AND tc.table_name=%s
"""
cursor = connection.cursor()
cursor.execute(sql, (ModelWithFkToPublicUser._meta.db_table, ))
fk_constraints = cursor.fetchall()
self.assertEqual(1, len(fk_constraints))
# The foreign key should reference the primary key of the user table
fk = fk_constraints[0]
self.assertEqual(User._meta.db_table, fk[3])
self.assertEqual('id', fk[4])
def test_direct_relation_to_public(self):
"""
Tests that a forward relationship through a foreign key to public from a model inside TENANT_APPS works.
"""
with tenant_context(self.tenant):
self.assertEqual(User.objects.get(pk=self.user1.id),
ModelWithFkToPublicUser.objects.get(pk=self.d1.id).user)
self.assertEqual(User.objects.get(pk=self.user2.id),
ModelWithFkToPublicUser.objects.get(pk=self.d2.id).user)
def test_reverse_relation_to_public(self):
"""
Tests that a reverse relationship through a foreign keys to public from a model inside TENANT_APPS works.
"""
with tenant_context(self.tenant):
users = User.objects.all().select_related().order_by('id')
self.assertEqual(ModelWithFkToPublicUser.objects.get(pk=self.d1.id),
users[0].modelwithfktopublicuser_set.all()[:1].get())
self.assertEqual(ModelWithFkToPublicUser.objects.get(pk=self.d2.id),
users[1].modelwithfktopublicuser_set.all()[:1].get())
class TenantTestCaseTest(BaseTestCase, TenantTestCase):
"""
Tests that the tenant created inside TenantTestCase persists on