summaryrefslogtreecommitdiff
path: root/django
diff options
context:
space:
mode:
authorBoulder Sprinters <boulder-sprinters@djangoproject.com>2007-05-07 15:50:55 +0000
committerBoulder Sprinters <boulder-sprinters@djangoproject.com>2007-05-07 15:50:55 +0000
commita275d3da8ed8cea8c2c92fc15151f43fb56b42ce (patch)
tree9f9a7c291956a17587b898772c5949b7a44864cd /django
parent0f22c6a7c8a089e2381a058b4c472cf92699950e (diff)
boulder-oracle-sprint: Merged to [5156]
git-svn-id: http://code.djangoproject.com/svn/django/branches/boulder-oracle-sprint@5157 bcc190cf-cafb-0310-a4f2-bffc1f526a37
Diffstat (limited to 'django')
-rw-r--r--django/db/models/query.py2
-rw-r--r--django/test/client.py80
-rw-r--r--django/test/testcases.py90
3 files changed, 129 insertions, 43 deletions
diff --git a/django/db/models/query.py b/django/db/models/query.py
index 93dcdd1776..d31ccf003e 100644
--- a/django/db/models/query.py
+++ b/django/db/models/query.py
@@ -998,7 +998,7 @@ def lookup_inner(path, lookup_type, value, opts, table, column):
field_choices(current_opts.get_all_related_many_to_many_objects(), True) + \
field_choices(current_opts.get_all_related_objects(), True) + \
field_choices(current_opts.fields, False)
- raise TypeError, "Cannot resolve keyword '%s' into field, choices are: %s" % (name, ", ".join(choices))
+ raise TypeError, "Cannot resolve keyword '%s' into field. Choices are: %s" % (name, ", ".join(choices))
# Check whether an intermediate join is required between current_table
# and new_table.
diff --git a/django/test/client.py b/django/test/client.py
index 95d3b85922..c3110f02ec 100644
--- a/django/test/client.py
+++ b/django/test/client.py
@@ -1,12 +1,16 @@
+import datetime
import sys
from cStringIO import StringIO
from urlparse import urlparse
from django.conf import settings
+from django.contrib.auth import authenticate, login
+from django.contrib.sessions.models import Session
+from django.contrib.sessions.middleware import SessionWrapper
from django.core.handlers.base import BaseHandler
from django.core.handlers.wsgi import WSGIRequest
from django.core.signals import got_request_exception
from django.dispatch import dispatcher
-from django.http import urlencode, SimpleCookie
+from django.http import urlencode, SimpleCookie, HttpRequest
from django.test import signals
from django.utils.functional import curry
@@ -113,7 +117,6 @@ class Client:
self.handler = ClientHandler()
self.defaults = defaults
self.cookies = SimpleCookie()
- self.session = {}
self.exc_info = None
def store_exc_info(self, *args, **kwargs):
@@ -123,6 +126,15 @@ class Client:
"""
self.exc_info = sys.exc_info()
+ def _session(self):
+ "Obtain the current session variables"
+ if 'django.contrib.sessions' in settings.INSTALLED_APPS:
+ cookie = self.cookies.get(settings.SESSION_COOKIE_NAME, None)
+ if cookie:
+ return SessionWrapper(cookie.value)
+ return {}
+ session = property(_session)
+
def request(self, **request):
"""
The master request method. Composes the environment dictionary
@@ -171,16 +183,10 @@ class Client:
if self.exc_info:
raise self.exc_info[1], None, self.exc_info[2]
- # Update persistent cookie and session data
+ # Update persistent cookie data
if response.cookies:
self.cookies.update(response.cookies)
- if 'django.contrib.sessions' in settings.INSTALLED_APPS:
- from django.contrib.sessions.middleware import SessionWrapper
- cookie = self.cookies.get(settings.SESSION_COOKIE_NAME, None)
- if cookie:
- self.session = SessionWrapper(cookie.value)
-
return response
def get(self, path, data={}, **extra):
@@ -215,42 +221,34 @@ class Client:
return self.request(**r)
- def login(self, path, username, password, **extra):
- """
- A specialized sequence of GET and POST to log into a view that
- is protected by a @login_required access decorator.
+ def login(self, **credentials):
+ """Set the Client to appear as if it has sucessfully logged into a site.
- path should be the URL of the page that is login protected.
-
- Returns the response from GETting the requested URL after
- login is complete. Returns False if login process failed.
+ Returns True if login is possible; False if the provided credentials
+ are incorrect, or if the Sessions framework is not available.
"""
- # First, GET the page that is login protected.
- # This page will redirect to the login page.
- response = self.get(path)
- if response.status_code != 302:
- return False
+ user = authenticate(**credentials)
+ if user and 'django.contrib.sessions' in settings.INSTALLED_APPS:
+ obj = Session.objects.get_new_session_object()
- _, _, login_path, _, data, _= urlparse(response['Location'])
- next = data.split('=')[1]
+ # Create a fake request to store login details
+ request = HttpRequest()
+ request.session = SessionWrapper(obj.session_key)
+ login(request, user)
- # Second, GET the login page; required to set up cookies
- response = self.get(login_path, **extra)
- if response.status_code != 200:
- return False
+ # Set the cookie to represent the session
+ self.cookies[settings.SESSION_COOKIE_NAME] = obj.session_key
+ self.cookies[settings.SESSION_COOKIE_NAME]['max-age'] = None
+ self.cookies[settings.SESSION_COOKIE_NAME]['path'] = '/'
+ self.cookies[settings.SESSION_COOKIE_NAME]['domain'] = settings.SESSION_COOKIE_DOMAIN
+ self.cookies[settings.SESSION_COOKIE_NAME]['secure'] = settings.SESSION_COOKIE_SECURE or None
+ self.cookies[settings.SESSION_COOKIE_NAME]['expires'] = None
- # Last, POST the login data.
- form_data = {
- 'username': username,
- 'password': password,
- 'next' : next,
- }
- response = self.post(login_path, data=form_data, **extra)
+ # Set the session values
+ Session.objects.save(obj.session_key, request.session._session,
+ datetime.datetime.now() + datetime.timedelta(seconds=settings.SESSION_COOKIE_AGE))
- # Login page should 302 redirect to the originally requested page
- if (response.status_code != 302 or
- urlparse(response['Location'])[2] != path):
+ return True
+ else:
return False
-
- # Since we are logged in, request the actual page again
- return self.get(path)
+ \ No newline at end of file
diff --git a/django/test/testcases.py b/django/test/testcases.py
index 2bfb9a733a..80f55b20d3 100644
--- a/django/test/testcases.py
+++ b/django/test/testcases.py
@@ -1,8 +1,10 @@
import re, doctest, unittest
+from urlparse import urlparse
from django.db import transaction
from django.core import management
from django.db.models import get_apps
-
+from django.test.client import Client
+
normalize_long_ints = lambda s: re.sub(r'(?<![\w])(\d+)L(?![\w])', '\\1', s)
class OutputChecker(doctest.OutputChecker):
@@ -46,5 +48,91 @@ class TestCase(unittest.TestCase):
super().
"""
+ self.client = Client()
self.install_fixtures()
super(TestCase, self).run(result)
+
+ def assertRedirects(self, response, expected_path):
+ """Assert that a response redirected to a specific URL, and that the
+ redirect URL can be loaded.
+
+ """
+ self.assertEqual(response.status_code, 302,
+ "Response didn't redirect: Reponse code was %d" % response.status_code)
+ scheme, netloc, path, params, query, fragment = urlparse(response['Location'])
+ self.assertEqual(path, expected_path,
+ "Response redirected to '%s', expected '%s'" % (path, expected_path))
+ redirect_response = self.client.get(path)
+ self.assertEqual(redirect_response.status_code, 200,
+ "Couldn't retrieve redirection page '%s'" % path)
+
+ def assertContains(self, response, text, count=1):
+ """Assert that a response indicates that a page was retreived successfully,
+ (i.e., the HTTP status code was 200), and that ``text`` occurs ``count``
+ times in the content of the response.
+
+ """
+ self.assertEqual(response.status_code, 200,
+ "Couldn't retrieve page'")
+ real_count = response.content.count(text)
+ self.assertEqual(real_count, count,
+ "Could only find %d of %d instances of '%s' in response" % (real_count, count, text))
+
+ def assertFormError(self, response, form, field, errors):
+ "Assert that a form used to render the response has a specific field error"
+ if not response.context:
+ self.fail('Response did not use any contexts to render the response')
+
+ # If there is a single context, put it into a list to simplify processing
+ if not isinstance(response.context, list):
+ contexts = [response.context]
+ else:
+ contexts = response.context
+
+ # If a single error string is provided, make it a list to simplify processing
+ if not isinstance(errors, list):
+ errors = [errors]
+
+ # Search all contexts for the error.
+ found_form = False
+ for i,context in enumerate(contexts):
+ if form in context:
+ found_form = True
+ try:
+ for err in errors:
+ if field:
+ self.assertTrue(err in context[form].errors[field],
+ "The field '%s' on form '%s' in context %d does not contain the error '%s' (actual errors: %s)" %
+ (field, form, i, err, list(context[form].errors[field])))
+ else:
+ self.assertTrue(err in context[form].non_field_errors(),
+ "The form '%s' in context %d does not contain the non-field error '%s' (actual errors: %s)" %
+ (form, i, err, list(context[form].non_field_errors())))
+ except KeyError:
+ self.fail("The form '%s' in context %d does not contain the field '%s'" % (form, i, field))
+ if not found_form:
+ self.fail("The form '%s' was not used to render the response" % form)
+
+ def assertTemplateUsed(self, response, template_name):
+ "Assert that the template with the provided name was used in rendering the response"
+ if isinstance(response.template, list):
+ template_names = [t.name for t in response.template]
+ self.assertTrue(template_name in template_names,
+ "Template '%s' was not one of the templates used to render the response. Templates used: %s" %
+ (template_name, template_names))
+ elif response.template:
+ self.assertEqual(template_name, response.template.name,
+ "Template '%s' was not used to render the response. Actual template was '%s'" %
+ (template_name, response.template.name))
+ else:
+ self.fail('No templates used to render the response')
+
+ def assertTemplateNotUsed(self, response, template_name):
+ "Assert that the template with the provided name was NOT used in rendering the response"
+ if isinstance(response.template, list):
+ self.assertFalse(template_name in [t.name for t in response.template],
+ "Template '%s' was used unexpectedly in rendering the response" % template_name)
+ elif response.template:
+ self.assertNotEqual(template_name, response.template.name,
+ "Template '%s' was used unexpectedly in rendering the response" % template_name)
+ \ No newline at end of file