Added a new TestCase class, subclassing django.test.TestCase, in order to
be able to add fixtures once and for all for all tests, instead of loading them again and again for each test, if running on a database that supports transaction rollbacks. In this case, fixtures specified in the perma_fixtures class attribute will be loaded permanently, and not re-loaded. Fixtures specifice as before, in a fixtures class attribute, will be treated as before. The downside of this is that as fixtures are loaded and not unloaded, they can conflict with each other. The requirements on consistency becomes much greater. The effect of this has been to require quite a bit of changes to the simplified creations of various objects in make_test_data() in cases where identically named objects occur in fixtures. Where completely fictitious objects are created, no conflicts appear. Also re-wrote parts of test_runner.py to permit global fixtures, loaded before any tests are run and shared by all. - Legacy-Id: 6318
This commit is contained in:
parent
4805b4b12e
commit
a07f47a4a0
|
@ -3,6 +3,7 @@
|
|||
from log import log
|
||||
from cache_foreign_key import FKAsOneToOne
|
||||
from draft_search import normalize_draftname
|
||||
from test_utils import TestCase
|
||||
|
||||
# See http://docs.python.org/tut/node8.html regarding the use of __all__ and
|
||||
# also regarding the practice of using "from xxx import *" in interactive
|
||||
|
|
|
@ -10,6 +10,8 @@ from ietf.name.models import *
|
|||
from ietf.group.models import *
|
||||
from ietf.person.models import *
|
||||
|
||||
import debug
|
||||
|
||||
def make_test_data():
|
||||
# telechat dates
|
||||
t = datetime.date.today()
|
||||
|
@ -21,7 +23,7 @@ def make_test_data():
|
|||
|
||||
# groups
|
||||
secretariat, created = Group.objects.get_or_create(
|
||||
name="Secretariat",
|
||||
name="IETF Secretariat",
|
||||
acronym="secretariat",
|
||||
state_id="active",
|
||||
type_id="ietf",
|
||||
|
@ -32,27 +34,39 @@ def make_test_data():
|
|||
state_id="active",
|
||||
type_id="ietf",
|
||||
parent=None)
|
||||
for x in ["irtf", "iab", "ise", "iesg"]:
|
||||
Group.objects.get_or_create(
|
||||
name=x.upper(),
|
||||
acronym=x,
|
||||
state_id="active",
|
||||
type_id="ietf",
|
||||
parent=None)
|
||||
area, created = Group.objects.get_or_create(
|
||||
|
||||
# XXX As given below, the group objects created doesn't match what's in the
|
||||
# fixtures, so if both are used, things blow up. The code below should
|
||||
# probably be updated to match what's in the fixtures, making the fixtures
|
||||
# unnecessary for a number of test cases.
|
||||
|
||||
# irtf, created = Group.objects.get_or_create(
|
||||
# name="IRTF",
|
||||
# acronym="irtf",
|
||||
# state_id="active",
|
||||
# type_id="irtf",
|
||||
# parent=None)
|
||||
# for g,t,n,p in [("iab","ietf", "Internet Architecture Board",1), ("ise","ietf", "Independent Submission Editor", None), ("iesg","ietf", "Internet Engineering Steering Group", 1), ]:
|
||||
# Group.objects.get_or_create(
|
||||
# name=n,
|
||||
# acronym=g,
|
||||
# state_id="active",
|
||||
# type_id=t,
|
||||
# parent_id=p)
|
||||
area = Group.objects.create(
|
||||
name="Far Future",
|
||||
acronym="farfut",
|
||||
state_id="active",
|
||||
type_id="area",
|
||||
parent=ietf)
|
||||
individ, created = Group.objects.get_or_create(
|
||||
name="Individual submissions",
|
||||
acronym="none",
|
||||
state_id="active",
|
||||
type_id="individ",
|
||||
parent=None)
|
||||
# individ, created = Group.objects.get_or_create(
|
||||
# name="Individual submissions",
|
||||
# acronym="none",
|
||||
# state_id="active",
|
||||
# type_id="individ",
|
||||
# parent=None)
|
||||
# mars WG
|
||||
group, created = Group.objects.get_or_create(
|
||||
group = Group.objects.create(
|
||||
name="Martian Special Interest Group",
|
||||
acronym="mars",
|
||||
state_id="active",
|
||||
|
@ -61,7 +75,7 @@ def make_test_data():
|
|||
list_email="mars-wg@ietf.org",
|
||||
)
|
||||
mars_wg = group
|
||||
charter, created = Document.objects.get_or_create(
|
||||
charter = Document.objects.create(
|
||||
name="charter-ietf-" + group.acronym,
|
||||
type_id="charter",
|
||||
title=group.name,
|
||||
|
@ -111,7 +125,7 @@ def make_test_data():
|
|||
# persons
|
||||
|
||||
# system
|
||||
system_person = Person.objects.create(
|
||||
system_person, created = Person.objects.get_or_create(
|
||||
# id=0, # special value
|
||||
name="(System)",
|
||||
ascii="(System)",
|
||||
|
@ -120,36 +134,35 @@ def make_test_data():
|
|||
system_person.save()
|
||||
|
||||
# IANA and RFC Editor groups
|
||||
iana = Group.objects.create(
|
||||
iana, created = Group.objects.get_or_create(
|
||||
name="IANA",
|
||||
acronym="iana",
|
||||
state_id="active",
|
||||
type_id="ietf",
|
||||
parent=None,
|
||||
)
|
||||
rfc_editor = Group.objects.create(
|
||||
rfc_editor, created = Group.objects.get_or_create(
|
||||
name="RFC Editor",
|
||||
acronym="rfceditor",
|
||||
state_id="active",
|
||||
type_id="ietf",
|
||||
type_id="rfcedtyp",
|
||||
parent=None,
|
||||
)
|
||||
|
||||
if system_person.id != 0: # work around bug in Django
|
||||
Person.objects.filter(id=system_person.id).update(id=0)
|
||||
system_person = Person.objects.get(id=0)
|
||||
|
||||
alias = Alias(person=system_person, name=system_person.name)
|
||||
alias.save()
|
||||
# if system_person.id != 0: # work around bug in Django
|
||||
# Person.objects.filter(id=system_person.id).update(id=0)
|
||||
# system_person = Person.objects.get(id=0)
|
||||
|
||||
Alias.objects.get_or_create(person=system_person, name=system_person.name)
|
||||
Email.objects.get_or_create(address="", person=system_person)
|
||||
|
||||
# plain IETF'er
|
||||
u = User.objects.create(username="plain")
|
||||
plainman = Person.objects.create(
|
||||
u, created = User.objects.get_or_create(username="plain")
|
||||
plainman, created = Person.objects.get_or_create(
|
||||
name="Plain Man",
|
||||
ascii="Plain Man",
|
||||
user=u)
|
||||
email = Email.objects.create(
|
||||
email, created = Email.objects.get_or_create(
|
||||
address="plain@example.com",
|
||||
person=plainman)
|
||||
|
||||
|
@ -308,15 +321,15 @@ def make_test_data():
|
|||
)
|
||||
|
||||
# Secretariat user
|
||||
u = User.objects.create(id=509, username="wnl")
|
||||
p = Person.objects.create(
|
||||
u, created = User.objects.get_or_create(id=509, username="wnl")
|
||||
p, created = Person.objects.get_or_create(
|
||||
name="Wanda Lo",
|
||||
ascii="Wanda Lo",
|
||||
user=u)
|
||||
email = Email.objects.create(
|
||||
email, created = Email.objects.get_or_create(
|
||||
address="wnl@amsl.com",
|
||||
person=p)
|
||||
Role.objects.create(
|
||||
Role.objects.get_or_create(
|
||||
name_id="auth",
|
||||
group=secretariat,
|
||||
email=email,
|
||||
|
|
|
@ -37,6 +37,7 @@ import socket
|
|||
from django.conf import settings
|
||||
from django.template import TemplateDoesNotExist
|
||||
from django.test.simple import run_tests as django_run_tests
|
||||
from django.core.management import call_command
|
||||
|
||||
import debug
|
||||
|
||||
|
@ -50,12 +51,14 @@ old_create = None
|
|||
def safe_create_1(self, verbosity, *args, **kwargs):
|
||||
global test_database_name, old_create
|
||||
print " Creating test database..."
|
||||
settings.DATABASES["default"]["OPTIONS"] = settings.DATABASE_TEST_OPTIONS
|
||||
print " Using OPTIONS: %s" % settings.DATABASES["default"]["OPTIONS"]
|
||||
x = old_create(self, 0, *args, **kwargs)
|
||||
print " Saving test database name "+settings.DATABASES["default"]["NAME"]+"..."
|
||||
test_database_name = settings.DATABASES["default"]["NAME"]
|
||||
return x
|
||||
if settings.DATABASES["default"]["ENGINE"] == 'django.db.backends.mysql':
|
||||
settings.DATABASES["default"]["OPTIONS"] = settings.DATABASE_TEST_OPTIONS
|
||||
print " Using OPTIONS: %s" % settings.DATABASES["default"]["OPTIONS"]
|
||||
test_database_name = old_create(self, 0, *args, **kwargs)
|
||||
if settings.GLOBAL_TEST_FIXTURES:
|
||||
print " Loading global test fixtures: %s" % ", ".join(settings.GLOBAL_TEST_FIXTURES)
|
||||
call_command('loaddata', *settings.GLOBAL_TEST_FIXTURES, verbosity=0, commit=False, database="default")
|
||||
return test_database_name
|
||||
|
||||
def safe_destroy_0_1(*args, **kwargs):
|
||||
global test_database_name, old_destroy
|
||||
|
|
|
@ -35,17 +35,21 @@
|
|||
import os
|
||||
import re
|
||||
import sys
|
||||
import django
|
||||
from django.db import connection
|
||||
from django.test import TestCase
|
||||
from django.test.client import Client
|
||||
import ietf.settings
|
||||
from django.conf import settings
|
||||
from datetime import datetime
|
||||
import urllib2 as urllib
|
||||
from difflib import unified_diff
|
||||
|
||||
real_database_name = ietf.settings.DATABASES["default"]["NAME"]
|
||||
import django.test
|
||||
from django.db import connection, connections, transaction, DEFAULT_DB_ALIAS
|
||||
from django.test.testcases import connections_support_transactions
|
||||
from django.test.testcases import disable_transaction_methods
|
||||
from django.test.client import Client
|
||||
from django.conf import settings
|
||||
from django.core.management import call_command
|
||||
|
||||
import debug
|
||||
|
||||
real_database_name = settings.DATABASES["default"]["NAME"]
|
||||
|
||||
import traceback
|
||||
|
||||
|
@ -57,7 +61,7 @@ class RealDatabaseTest:
|
|||
self._setDatabaseName(newdb)
|
||||
|
||||
def tearDownRealDatabase(self):
|
||||
curdb = self._getDatabaseName()
|
||||
#curdb = self._getDatabaseName()
|
||||
#print " Switching database from "+curdb+" to "+self._original_testdb
|
||||
self._setDatabaseName(self._original_testdb)
|
||||
|
||||
|
@ -105,7 +109,7 @@ def split_url(url):
|
|||
args = {}
|
||||
return url, args
|
||||
|
||||
class SimpleUrlTestCase(TestCase,RealDatabaseTest):
|
||||
class SimpleUrlTestCase(django.test.TestCase,RealDatabaseTest):
|
||||
|
||||
def setUp(self):
|
||||
self.setUpRealDatabase()
|
||||
|
@ -158,7 +162,8 @@ class SimpleUrlTestCase(TestCase,RealDatabaseTest):
|
|||
if code in codes:
|
||||
sys.stdout.write(".")
|
||||
else:
|
||||
sys.stdout.write("E")
|
||||
sys.stdout.write("F")
|
||||
failed = True
|
||||
elif self.verbosity > 1:
|
||||
if code in codes:
|
||||
print "OK %s %s" % (code, url)
|
||||
|
@ -232,7 +237,72 @@ def login_testing_unauthorized(tc, remote_user, url):
|
|||
|
||||
tc.client.login(remote_user=remote_user)
|
||||
|
||||
class ReverseLazyTest(TestCase):
|
||||
class ReverseLazyTest(django.test.TestCase):
|
||||
def test_redirect_with_lazy_reverse(self):
|
||||
response = self.client.get('/ipr/update/')
|
||||
self.assertRedirects(response, "/ipr/", status_code=301)
|
||||
|
||||
loaded_fixtures = []
|
||||
|
||||
class TestCase(django.test.TestCase):
|
||||
"""
|
||||
Does basically the same as django.test.TestCase, but if the test database has
|
||||
support for transactions, it loads perma_fixtures before the transaction which
|
||||
surrounds every test. This causes the perma_fixtures to stay in the database
|
||||
after the transaction which surrounds each test is rolled back, which lets us
|
||||
load each preload_fixture only once. However, it requires that all the
|
||||
perma_fixtures are consistent with each other and with all regular fixtures
|
||||
across all applications. You could view the perma_fixtures as on_the_fly
|
||||
initial_data for tests.
|
||||
|
||||
Regular fixtures are re-loaded for each TestCase, as usual.
|
||||
|
||||
We don't flush the database, as that triggers a re-load of initial_data.
|
||||
"""
|
||||
|
||||
def _fixture_setup(self):
|
||||
global loaded_fixtures
|
||||
|
||||
if not connections_support_transactions():
|
||||
if hasattr(self, 'perma_fixtures'):
|
||||
if not hasattr(self, 'fixtures'):
|
||||
self.fixtures = self.perma_fixtures
|
||||
else:
|
||||
self.fixtures += self.perma_fixtures
|
||||
return super(TestCase, self)._fixture_setup()
|
||||
|
||||
# If the test case has a multi_db=True flag, setup all databases.
|
||||
# Otherwise, just use default.
|
||||
if getattr(self, 'multi_db', False):
|
||||
databases = connections
|
||||
else:
|
||||
databases = [DEFAULT_DB_ALIAS]
|
||||
|
||||
for db in databases:
|
||||
if hasattr(self, 'perma_fixtures'):
|
||||
fixtures = [ fixture for fixture in self.perma_fixtures if not fixture in loaded_fixtures ]
|
||||
if fixtures:
|
||||
call_command('loaddata', *fixtures, **{
|
||||
'verbosity': 0,
|
||||
'commit': False,
|
||||
'database': db
|
||||
})
|
||||
loaded_fixtures += fixtures
|
||||
|
||||
for db in databases:
|
||||
transaction.enter_transaction_management(using=db)
|
||||
transaction.managed(True, using=db)
|
||||
disable_transaction_methods()
|
||||
|
||||
from django.contrib.sites.models import Site
|
||||
Site.objects.clear_cache()
|
||||
|
||||
for db in databases:
|
||||
if hasattr(self, 'fixtures'):
|
||||
call_command('loaddata', *self.fixtures, **{
|
||||
'verbosity': 0,
|
||||
'commit': False,
|
||||
'database': db
|
||||
})
|
||||
|
||||
|
||||
|
|
Loading…
Reference in a new issue