diff --git a/.travis.yml b/.travis.yml index 9344632fc..7c6253129 100644 --- a/.travis.yml +++ b/.travis.yml @@ -1,5 +1,6 @@ language: python python: - "2.7" + - "2.6" install: "pip install -r requirements.txt --use-mirrors" -script: python demo_app/manage.py validate \ No newline at end of file +script: "cd tests/ && python runtests.py" \ No newline at end of file diff --git a/setup.py b/setup.py index 57fc85695..b4c2601a3 100644 --- a/setup.py +++ b/setup.py @@ -13,8 +13,7 @@ author_email='sshwsfc@gmail.com', url='http://www.xadmin.io', download_url='http://github.com/sshwsfc/django-xadmin/archive/master.zip', - packages=['xadmin', 'xadmin.plugins', 'xadmin.templatetags', - 'xadmin.tests', 'xadmin.views'], + packages=['xadmin', 'xadmin.plugins', 'xadmin.templatetags', 'xadmin.views'], include_package_data=True, install_requires=[ 'setuptools', diff --git a/tests/__init__.py b/tests/__init__.py new file mode 100644 index 000000000..e69de29bb diff --git a/tests/runtests.py b/tests/runtests.py new file mode 100755 index 000000000..60fbb1251 --- /dev/null +++ b/tests/runtests.py @@ -0,0 +1,165 @@ +#!/usr/bin/env python +import os +import shutil +import sys +import tempfile + +TEST_ROOT = os.path.realpath(os.path.dirname(__file__)) +sys.path.insert(0, os.path.join(TEST_ROOT, os.pardir)) + +RUNTESTS_DIR = os.path.join(TEST_ROOT, 'xtests') +TEST_TEMPLATE_DIR = 'templates' +TEMP_DIR = tempfile.mkdtemp(prefix='django_') +os.environ['DJANGO_TEST_TEMP_DIR'] = TEMP_DIR + +ALWAYS_INSTALLED_APPS = [ + 'django.contrib.auth', + 'django.contrib.contenttypes', + 'django.contrib.sessions', + 'django.contrib.messages', + 'django.contrib.staticfiles', + + 'xadmin', + 'crispy_forms', + 'reversion', +] + +def get_test_modules(): + modules = [] + for f in os.listdir(RUNTESTS_DIR): + if (f.startswith('__init__') or + f.startswith('.') or + f.startswith('sql')): + continue + modules.append(f) + return modules + +def setup(verbosity, test_labels): + from django.conf import settings + state = { + 'INSTALLED_APPS': settings.INSTALLED_APPS, + 'ROOT_URLCONF': getattr(settings, "ROOT_URLCONF", ""), + 'TEMPLATE_DIRS': settings.TEMPLATE_DIRS, + 'USE_I18N': settings.USE_I18N, + 'LOGIN_URL': settings.LOGIN_URL, + 'LANGUAGE_CODE': settings.LANGUAGE_CODE, + 'MIDDLEWARE_CLASSES': settings.MIDDLEWARE_CLASSES, + 'STATIC_URL': settings.STATIC_URL, + 'STATIC_ROOT': settings.STATIC_ROOT, + } + + # Redirect some settings for the duration of these tests. + settings.INSTALLED_APPS = ALWAYS_INSTALLED_APPS + settings.ROOT_URLCONF = 'urls' + settings.STATIC_URL = '/static/' + settings.STATIC_ROOT = os.path.join(TEMP_DIR, 'static') + settings.TEMPLATE_DIRS = (os.path.join(RUNTESTS_DIR, TEST_TEMPLATE_DIR),) + settings.USE_I18N = True + settings.LANGUAGE_CODE = 'en' + settings.MIDDLEWARE_CLASSES = ( + 'django.contrib.sessions.middleware.SessionMiddleware', + 'django.contrib.auth.middleware.AuthenticationMiddleware', + 'django.contrib.messages.middleware.MessageMiddleware', + 'django.middleware.common.CommonMiddleware', + ) + settings.SITE_ID = 1 + # For testing comment-utils, we require the MANAGERS attribute + # to be set, so that a test email is sent out which we catch + # in our tests. + settings.MANAGERS = ("admin@xadmin.io",) + + # Load all the ALWAYS_INSTALLED_APPS. + # (This import statement is intentionally delayed until after we + # access settings because of the USE_I18N dependency.) + from django.db.models.loading import get_apps, load_app + get_apps() + + # Load all the test model apps. + test_labels_set = set([label.split('.')[0] for label in test_labels]) + test_modules = get_test_modules() + + for module_name in test_modules: + module_label = '.'.join(['xtests', module_name]) + # if the module was named on the command line, or + # no modules were named (i.e., run all), import + # this module and add it to the list to test. + if not test_labels or module_name in test_labels_set: + if verbosity >= 2: + print "Importing application %s" % module_name + mod = load_app(module_label) + if mod: + if module_label not in settings.INSTALLED_APPS: + settings.INSTALLED_APPS.append(module_label) + + return state + +def teardown(state): + from django.conf import settings + # Removing the temporary TEMP_DIR. Ensure we pass in unicode + # so that it will successfully remove temp trees containing + # non-ASCII filenames on Windows. (We're assuming the temp dir + # name itself does not contain non-ASCII characters.) + shutil.rmtree(unicode(TEMP_DIR)) + # Restore the old settings. + for key, value in state.items(): + setattr(settings, key, value) + +def django_tests(verbosity, interactive, failfast, test_labels): + from django.conf import settings + state = setup(verbosity, test_labels) + extra_tests = [] + + # Run the test suite, including the extra validation tests. + from django.test.utils import get_runner + if not hasattr(settings, 'TEST_RUNNER'): + settings.TEST_RUNNER = 'django.test.simple.DjangoTestSuiteRunner' + TestRunner = get_runner(settings) + + test_runner = TestRunner(verbosity=verbosity, interactive=interactive, + failfast=failfast) + failures = test_runner.run_tests(test_labels or get_test_modules(), extra_tests=extra_tests) + + teardown(state) + return failures + +if __name__ == "__main__": + from optparse import OptionParser + usage = "%prog [options] [module module module ...]" + parser = OptionParser(usage=usage) + parser.add_option( + '-v','--verbosity', action='store', dest='verbosity', default='1', + type='choice', choices=['0', '1', '2', '3'], + help='Verbosity level; 0=minimal output, 1=normal output, 2=all ' + 'output') + parser.add_option( + '--noinput', action='store_false', dest='interactive', default=True, + help='Tells Django to NOT prompt the user for input of any kind.') + parser.add_option( + '--failfast', action='store_true', dest='failfast', default=False, + help='Tells Django to stop running the test suite after first failed ' + 'test.') + parser.add_option( + '--settings', + help='Python path to settings module, e.g. "myproject.settings". If ' + 'this isn\'t provided, the DJANGO_SETTINGS_MODULE environment ' + 'variable will be used.') + parser.add_option( + '--liveserver', action='store', dest='liveserver', default=None, + help='Overrides the default address where the live server (used with ' + 'LiveServerTestCase) is expected to run from. The default value ' + 'is localhost:8081.'), + options, args = parser.parse_args() + if options.settings: + os.environ['DJANGO_SETTINGS_MODULE'] = options.settings + elif "DJANGO_SETTINGS_MODULE" not in os.environ: + os.environ['DJANGO_SETTINGS_MODULE'] = 'settings' + else: + options.settings = os.environ['DJANGO_SETTINGS_MODULE'] + + if options.liveserver is not None: + os.environ['DJANGO_LIVE_TEST_SERVER_ADDRESS'] = options.liveserver + + failures = django_tests(int(options.verbosity), options.interactive, + options.failfast, args) + if failures: + sys.exit(bool(failures)) diff --git a/tests/settings.py b/tests/settings.py new file mode 100644 index 000000000..f1bfda658 --- /dev/null +++ b/tests/settings.py @@ -0,0 +1,12 @@ +DEBUG = True +DATABASES = { + 'default': { + 'ENGINE': 'django.db.backends.sqlite3', + } +} + +# Required for Django 1.4+ +STATIC_URL = '/static/' + +# Required for Django 1.5+ +SECRET_KEY = 'abc123' diff --git a/tests/xtests/__init__.py b/tests/xtests/__init__.py new file mode 100644 index 000000000..e69de29bb diff --git a/tests/xtests/site/__init__.py b/tests/xtests/site/__init__.py new file mode 100644 index 000000000..e69de29bb diff --git a/tests/xtests/site/models.py b/tests/xtests/site/models.py new file mode 100644 index 000000000..0bc63e7ee --- /dev/null +++ b/tests/xtests/site/models.py @@ -0,0 +1,5 @@ +from django.db import models + + +class ModelA(models.Model): + name = models.CharField(max_length=64) \ No newline at end of file diff --git a/xadmin/tests/sites.py b/tests/xtests/site/tests.py similarity index 78% rename from xadmin/tests/sites.py rename to tests/xtests/site/tests.py index 6ee80152c..eb569d18b 100644 --- a/xadmin/tests/sites.py +++ b/tests/xtests/site/tests.py @@ -1,5 +1,7 @@ -from xadmin.tests.base import TestCase +from django.test import TestCase from django.http import HttpResponse +from django.contrib.auth.models import User +from django.test.client import RequestFactory from xadmin.sites import AdminSite from xadmin.views import BaseAdminView, BaseAdminPlugin, ModelAdminView, filter_hook @@ -40,6 +42,18 @@ def get(self, request, obj_id): class AdminSiteTest(TestCase): + def setUp(self): + # Every test needs access to the request factory. + self.factory = RequestFactory() + + def _create_superuser(self, username): + return User.objects.create(username=username, is_superuser=True) + + def _mocked_authenticated_request(self, url, user): + request = self.factory.get(url) + request.user = user + return request + def get_site(self): return AdminSite('test', 'test_app') @@ -76,7 +90,8 @@ def test_plugin(self): c = site.get_view_class(TestAdminView) self.assertIn(TestPlugin, c.plugin_classes) - cv = c(self.get_factory().get('test/')) + admin = self._create_superuser('admin') + cv = c(self._mocked_authenticated_request('test/', admin)) self.assertEqual(cv.get_title(), "TEST TITLE PLUGIN") diff --git a/tests/xtests/views/__init__.py b/tests/xtests/views/__init__.py new file mode 100644 index 000000000..e69de29bb diff --git a/tests/xtests/views/models.py b/tests/xtests/views/models.py new file mode 100644 index 000000000..e69de29bb diff --git a/tests/xtests/views/tests.py b/tests/xtests/views/tests.py new file mode 100644 index 000000000..f64d821a4 --- /dev/null +++ b/tests/xtests/views/tests.py @@ -0,0 +1,6 @@ +from django.test import TestCase + + +class ListViewTest(TestCase): + + pass diff --git a/xadmin/tests/__init__.py b/xadmin/tests/__init__.py deleted file mode 100644 index 7fc815114..000000000 --- a/xadmin/tests/__init__.py +++ /dev/null @@ -1,3 +0,0 @@ -from xadmin.tests.sites import * -from xadmin.tests.views import * -from xadmin.tests.plugins import * diff --git a/xadmin/tests/views/__init__.py b/xadmin/tests/views/__init__.py deleted file mode 100644 index 9b356ed48..000000000 --- a/xadmin/tests/views/__init__.py +++ /dev/null @@ -1,2 +0,0 @@ -from xadmin.tests.views.base import * -from xadmin.tests.views.model import * diff --git a/xadmin/tests/views/model.py b/xadmin/tests/views/model.py deleted file mode 100644 index fbb6198ae..000000000 --- a/xadmin/tests/views/model.py +++ /dev/null @@ -1,8 +0,0 @@ -from xadmin.tests.base import TestCase - - -class DeleteTest(TestCase): - - def test_delete(self): - c = self.get_client() - response = c.get('/')