wagtail/wagtail/wagtailredirects/tests.py

493 lines
22 KiB
Python

from __future__ import absolute_import, unicode_literals
from django.core.urlresolvers import reverse
from django.test import TestCase
from wagtail.tests.utils import WagtailTestUtils
from wagtail.wagtailcore.models import Page, Site
from wagtail.wagtailredirects import models
class TestRedirects(TestCase):
fixtures = ['test.json']
def test_path_normalisation(self):
# Shortcut to normalise function (to keep things tidy)
normalise_path = models.Redirect.normalise_path
# Create a path
path = normalise_path('/Hello/world.html;fizz=three;buzz=five?foo=Bar&Baz=quux2')
# Test against equivalant paths
self.assertEqual(path, normalise_path( # The exact same URL
'/Hello/world.html;fizz=three;buzz=five?foo=Bar&Baz=quux2'
))
self.assertEqual(path, normalise_path( # Scheme, hostname and port ignored
'http://mywebsite.com:8000/Hello/world.html;fizz=three;buzz=five?foo=Bar&Baz=quux2'
))
self.assertEqual(path, normalise_path( # Leading slash can be omitted
'Hello/world.html;fizz=three;buzz=five?foo=Bar&Baz=quux2'
))
self.assertEqual(path, normalise_path( # Trailing slashes are ignored
'Hello/world.html/;fizz=three;buzz=five?foo=Bar&Baz=quux2'
))
self.assertEqual(path, normalise_path( # Fragments are ignored
'/Hello/world.html;fizz=three;buzz=five?foo=Bar&Baz=quux2#cool'
))
self.assertEqual(path, normalise_path( # Order of query string parameters is ignored
'/Hello/world.html;fizz=three;buzz=five?Baz=quux2&foo=Bar'
))
self.assertEqual(path, normalise_path( # Order of parameters is ignored
'/Hello/world.html;buzz=five;fizz=three?foo=Bar&Baz=quux2'
))
self.assertEqual(path, normalise_path( # Leading whitespace
' /Hello/world.html;fizz=three;buzz=five?foo=Bar&Baz=quux2'
))
self.assertEqual(path, normalise_path( # Trailing whitespace
'/Hello/world.html;fizz=three;buzz=five?foo=Bar&Baz=quux2 '
))
# Test against different paths
self.assertNotEqual(path, normalise_path( # 'hello' is lowercase
'/hello/world.html;fizz=three;buzz=five?foo=Bar&Baz=quux2'
))
self.assertNotEqual(path, normalise_path( # No '.html'
'/Hello/world;fizz=three;buzz=five?foo=Bar&Baz=quux2'
))
self.assertNotEqual(path, normalise_path( # Query string parameter value has wrong case
'/Hello/world.html;fizz=three;buzz=five?foo=bar&Baz=Quux2'
))
self.assertNotEqual(path, normalise_path( # Query string parameter name has wrong case
'/Hello/world.html;fizz=three;buzz=five?foo=Bar&baz=quux2'
))
self.assertNotEqual(path, normalise_path( # Parameter value has wrong case
'/Hello/world.html;fizz=three;buzz=Five?foo=Bar&Baz=quux2'
))
self.assertNotEqual(path, normalise_path( # Parameter name has wrong case
'/Hello/world.html;Fizz=three;buzz=five?foo=Bar&Baz=quux2'
))
self.assertNotEqual(path, normalise_path( # Missing params
'/Hello/world.html?foo=Bar&Baz=quux2'
))
self.assertNotEqual(path, normalise_path( # 'WORLD' is uppercase
'/Hello/WORLD.html;fizz=three;buzz=five?foo=Bar&Baz=quux2'
))
self.assertNotEqual(path, normalise_path( # '.htm' is not the same as '.html'
'/Hello/world.htm;fizz=three;buzz=five?foo=Bar&Baz=quux2'
))
self.assertEqual('/', normalise_path('/')) # '/' should stay '/'
# Normalise some rubbish to make sure it doesn't crash
normalise_path('This is not a URL')
normalise_path('//////hello/world')
normalise_path('!#@%$*')
normalise_path('C:\\Program Files (x86)\\Some random program\\file.txt')
def test_basic_redirect(self):
# Create a redirect
redirect = models.Redirect(old_path='/redirectme', redirect_link='/redirectto')
redirect.save()
# Navigate to it
response = self.client.get('/redirectme/')
# Check that we were redirected
self.assertRedirects(response, '/redirectto', status_code=301, fetch_redirect_response=False)
def test_temporary_redirect(self):
# Create a redirect
redirect = models.Redirect(old_path='/redirectme', redirect_link='/redirectto', is_permanent=False)
redirect.save()
# Navigate to it
response = self.client.get('/redirectme/')
# Check that we were redirected temporarily
self.assertRedirects(response, '/redirectto', status_code=302, fetch_redirect_response=False)
def test_redirect_stripping_query_string(self):
# Create a redirect which includes a query string
redirect_with_query_string = models.Redirect(
old_path='/redirectme?foo=Bar', redirect_link='/with-query-string-only'
)
redirect_with_query_string.save()
# ... and another redirect without the query string
redirect_without_query_string = models.Redirect(old_path='/redirectme', redirect_link='/without-query-string')
redirect_without_query_string.save()
# Navigate to the redirect with the query string
r_matching_qs = self.client.get('/redirectme/?foo=Bar')
self.assertRedirects(r_matching_qs, '/with-query-string-only', status_code=301, fetch_redirect_response=False)
# Navigate to the redirect with a different query string
# This should strip out the query string and match redirect_without_query_string
r_no_qs = self.client.get('/redirectme/?utm_source=irrelevant')
self.assertRedirects(r_no_qs, '/without-query-string', status_code=301, fetch_redirect_response=False)
def test_redirect_to_page(self):
christmas_page = Page.objects.get(url_path='/home/events/christmas/')
models.Redirect.objects.create(old_path='/xmas', redirect_page=christmas_page)
response = self.client.get('/xmas/', HTTP_HOST='test.example.com')
self.assertRedirects(response, 'http://test.example.com/events/christmas/', status_code=301, fetch_redirect_response=False)
def test_redirect_from_any_site(self):
contact_page = Page.objects.get(url_path='/home/contact-us/')
Site.objects.create(hostname='other.example.com', port=80, root_page=contact_page)
christmas_page = Page.objects.get(url_path='/home/events/christmas/')
models.Redirect.objects.create(old_path='/xmas', redirect_page=christmas_page)
# no site was specified on the redirect, so it should redirect regardless of hostname
response = self.client.get('/xmas/', HTTP_HOST='localhost')
self.assertRedirects(response, 'http://localhost/events/christmas/', status_code=301, fetch_redirect_response=False)
response = self.client.get('/xmas/', HTTP_HOST='other.example.com')
self.assertRedirects(response, 'http://localhost/events/christmas/', status_code=301, fetch_redirect_response=False)
def test_redirect_from_specific_site(self):
contact_page = Page.objects.get(url_path='/home/contact-us/')
other_site = Site.objects.create(hostname='other.example.com', port=80, root_page=contact_page)
christmas_page = Page.objects.get(url_path='/home/events/christmas/')
models.Redirect.objects.create(old_path='/xmas', redirect_page=christmas_page, site=other_site)
# redirect should only respond when site is other_site
response = self.client.get('/xmas/', HTTP_HOST='other.example.com')
self.assertRedirects(response, 'http://localhost/events/christmas/', status_code=301, fetch_redirect_response=False)
response = self.client.get('/xmas/', HTTP_HOST='localhost')
self.assertEqual(response.status_code, 404)
def test_duplicate_redirects_when_match_is_for_generic(self):
contact_page = Page.objects.get(url_path='/home/contact-us/')
site = Site.objects.create(hostname='other.example.com', port=80, root_page=contact_page)
# two redirects, one for any site, one for specific
models.Redirect.objects.create(old_path='/xmas', redirect_link='/generic')
models.Redirect.objects.create(site=site, old_path='/xmas', redirect_link='/site-specific')
response = self.client.get('/xmas/')
# the redirect which matched was /generic
self.assertRedirects(response, '/generic', status_code=301, fetch_redirect_response=False)
def test_duplicate_redirects_with_query_string_when_match_is_for_generic(self):
contact_page = Page.objects.get(url_path='/home/contact-us/')
site = Site.objects.create(hostname='other.example.com', port=80, root_page=contact_page)
# two redirects, one for any site, one for specific, both with query string
models.Redirect.objects.create(old_path='/xmas?foo=Bar', redirect_link='/generic-with-query-string')
models.Redirect.objects.create(site=site, old_path='/xmas?foo=Bar', redirect_link='/site-specific-with-query-string')
# and two redirects, one for any site, one for specific, without query strings
models.Redirect.objects.create(old_path='/xmas', redirect_link='/generic')
models.Redirect.objects.create(site=site, old_path='/xmas', redirect_link='/site-specific')
response = self.client.get('/xmas/?foo=Bar')
# the redirect which matched was /generic-with-query-string
self.assertRedirects(response, '/generic-with-query-string', status_code=301, fetch_redirect_response=False)
# now use a non-matching query string
response = self.client.get('/xmas/?foo=Baz')
# the redirect which matched was /generic
self.assertRedirects(response, '/generic', status_code=301, fetch_redirect_response=False)
def test_duplicate_redirects_when_match_is_for_specific(self):
contact_page = Page.objects.get(url_path='/home/contact-us/')
site = Site.objects.create(hostname='other.example.com', port=80, root_page=contact_page)
# two redirects, one for any site, one for specific
models.Redirect.objects.create(old_path='/xmas', redirect_link='/generic')
models.Redirect.objects.create(site=site, old_path='/xmas', redirect_link='/site-specific')
response = self.client.get('/xmas/', HTTP_HOST='other.example.com')
# the redirect which matched was /site-specific
self.assertRedirects(response, 'http://other.example.com/site-specific', status_code=301, fetch_redirect_response=False)
def test_duplicate_redirects_with_query_string_when_match_is_for_specific_with_qs(self):
contact_page = Page.objects.get(url_path='/home/contact-us/')
site = Site.objects.create(hostname='other.example.com', port=80, root_page=contact_page)
# two redirects, one for any site, one for specific, both with query string
models.Redirect.objects.create(old_path='/xmas?foo=Bar', redirect_link='/generic-with-query-string')
models.Redirect.objects.create(site=site, old_path='/xmas?foo=Bar', redirect_link='/site-specific-with-query-string')
# and two redirects, one for any site, one for specific, without query strings
models.Redirect.objects.create(old_path='/xmas', redirect_link='/generic')
models.Redirect.objects.create(site=site, old_path='/xmas', redirect_link='/site-specific')
response = self.client.get('/xmas/?foo=Bar', HTTP_HOST='other.example.com')
# the redirect which matched was /site-specific-with-query-string
self.assertRedirects(response, 'http://other.example.com/site-specific-with-query-string', status_code=301, fetch_redirect_response=False)
# now use a non-matching query string
response = self.client.get('/xmas/?foo=Baz', HTTP_HOST='other.example.com')
# the redirect which matched was /site-specific
self.assertRedirects(response, 'http://other.example.com/site-specific', status_code=301, fetch_redirect_response=False)
def test_duplicate_page_redirects_when_match_is_for_specific(self):
contact_page = Page.objects.get(url_path='/home/contact-us/')
site = Site.objects.create(hostname='other.example.com', port=80, root_page=contact_page)
christmas_page = Page.objects.get(url_path='/home/events/christmas/')
# two redirects, one for any site, one for specific
models.Redirect.objects.create(old_path='/xmas', redirect_page=contact_page)
models.Redirect.objects.create(site=site, old_path='/xmas', redirect_page=christmas_page)
# request for specific site gets the christmas_page redirect, not accessible from other.example.com
response = self.client.get('/xmas/', HTTP_HOST='other.example.com')
self.assertRedirects(response, 'http://localhost/events/christmas/', status_code=301, fetch_redirect_response=False)
class TestRedirectsIndexView(TestCase, WagtailTestUtils):
def setUp(self):
self.login()
def get(self, params={}):
return self.client.get(reverse('wagtailredirects:index'), params)
def test_simple(self):
response = self.get()
self.assertEqual(response.status_code, 200)
self.assertTemplateUsed(response, 'wagtailredirects/index.html')
def test_search(self):
response = self.get({'q': "Hello"})
self.assertEqual(response.status_code, 200)
self.assertEqual(response.context['query_string'], "Hello")
def test_pagination(self):
pages = ['0', '1', '-1', '9999', 'Not a page']
for page in pages:
response = self.get({'p': page})
self.assertEqual(response.status_code, 200)
class TestRedirectsAddView(TestCase, WagtailTestUtils):
fixtures = ['test.json']
def setUp(self):
self.login()
def get(self, params={}):
return self.client.get(reverse('wagtailredirects:add'), params)
def post(self, post_data={}):
return self.client.post(reverse('wagtailredirects:add'), post_data)
def test_simple(self):
response = self.get()
self.assertEqual(response.status_code, 200)
self.assertTemplateUsed(response, 'wagtailredirects/add.html')
def test_add(self):
response = self.post({
'old_path': '/test',
'site': '',
'is_permanent': 'on',
'redirect_link': 'http://www.test.com/',
})
# Should redirect back to index
self.assertRedirects(response, reverse('wagtailredirects:index'))
# Check that the redirect was created
redirects = models.Redirect.objects.filter(old_path='/test')
self.assertEqual(redirects.count(), 1)
self.assertEqual(redirects.first().redirect_link, 'http://www.test.com/')
self.assertEqual(redirects.first().site, None)
def test_add_with_site(self):
localhost = Site.objects.get(hostname='localhost')
response = self.post({
'old_path': '/test',
'site': localhost.id,
'is_permanent': 'on',
'redirect_link': 'http://www.test.com/',
})
# Should redirect back to index
self.assertRedirects(response, reverse('wagtailredirects:index'))
# Check that the redirect was created
redirects = models.Redirect.objects.filter(old_path='/test')
self.assertEqual(redirects.count(), 1)
self.assertEqual(redirects.first().redirect_link, 'http://www.test.com/')
self.assertEqual(redirects.first().site, localhost)
def test_add_validation_error(self):
response = self.post({
'old_path': '',
'site': '',
'is_permanent': 'on',
'redirect_link': 'http://www.test.com/',
})
# Should not redirect to index
self.assertEqual(response.status_code, 200)
def test_cannot_add_duplicate_with_no_site(self):
models.Redirect.objects.create(old_path='/test', site=None, redirect_link='http://elsewhere.com/')
response = self.post({
'old_path': '/test',
'site': '',
'is_permanent': 'on',
'redirect_link': 'http://www.test.com/',
})
# Should not redirect to index
self.assertEqual(response.status_code, 200)
def test_cannot_add_duplicate_on_same_site(self):
localhost = Site.objects.get(hostname='localhost')
models.Redirect.objects.create(old_path='/test', site=localhost, redirect_link='http://elsewhere.com/')
response = self.post({
'old_path': '/test',
'site': localhost.pk,
'is_permanent': 'on',
'redirect_link': 'http://www.test.com/',
})
# Should not redirect to index
self.assertEqual(response.status_code, 200)
def test_can_reuse_path_on_other_site(self):
localhost = Site.objects.get(hostname='localhost')
contact_page = Page.objects.get(url_path='/home/contact-us/')
other_site = Site.objects.create(hostname='other.example.com', port=80, root_page=contact_page)
models.Redirect.objects.create(old_path='/test', site=localhost, redirect_link='http://elsewhere.com/')
response = self.post({
'old_path': '/test',
'site': other_site.pk,
'is_permanent': 'on',
'redirect_link': 'http://www.test.com/',
})
# Should redirect back to index
self.assertRedirects(response, reverse('wagtailredirects:index'))
# Check that the redirect was created
redirects = models.Redirect.objects.filter(redirect_link='http://www.test.com/')
self.assertEqual(redirects.count(), 1)
class TestRedirectsEditView(TestCase, WagtailTestUtils):
def setUp(self):
# Create a redirect to edit
self.redirect = models.Redirect(old_path='/test', redirect_link='http://www.test.com/')
self.redirect.save()
# Login
self.login()
def get(self, params={}, redirect_id=None):
return self.client.get(reverse('wagtailredirects:edit', args=(redirect_id or self.redirect.id, )), params)
def post(self, post_data={}, redirect_id=None):
return self.client.post(reverse('wagtailredirects:edit', args=(redirect_id or self.redirect.id, )), post_data)
def test_simple(self):
response = self.get()
self.assertEqual(response.status_code, 200)
self.assertTemplateUsed(response, 'wagtailredirects/edit.html')
def test_nonexistant_redirect(self):
self.assertEqual(self.get(redirect_id=100000).status_code, 404)
def test_edit(self):
response = self.post({
'old_path': '/test',
'is_permanent': 'on',
'site': '',
'redirect_link': 'http://www.test.com/ive-been-edited',
})
# Should redirect back to index
self.assertRedirects(response, reverse('wagtailredirects:index'))
# Check that the redirect was edited
redirects = models.Redirect.objects.filter(old_path='/test')
self.assertEqual(redirects.count(), 1)
self.assertEqual(redirects.first().redirect_link, 'http://www.test.com/ive-been-edited')
self.assertEqual(redirects.first().site, None)
def test_edit_with_site(self):
localhost = Site.objects.get(hostname='localhost')
response = self.post({
'old_path': '/test',
'is_permanent': 'on',
'site': localhost.id,
'redirect_link': 'http://www.test.com/ive-been-edited',
})
# Should redirect back to index
self.assertRedirects(response, reverse('wagtailredirects:index'))
# Check that the redirect was edited
redirects = models.Redirect.objects.filter(old_path='/test')
self.assertEqual(redirects.count(), 1)
self.assertEqual(redirects.first().redirect_link, 'http://www.test.com/ive-been-edited')
self.assertEqual(redirects.first().site, localhost)
def test_edit_validation_error(self):
response = self.post({
'old_path': '',
'is_permanent': 'on',
'site': '',
'redirect_link': 'http://www.test.com/ive-been-edited',
})
# Should not redirect to index
self.assertEqual(response.status_code, 200)
def test_edit_duplicate(self):
models.Redirect.objects.create(old_path='/othertest', site=None, redirect_link='http://elsewhere.com/')
response = self.post({
'old_path': '/othertest',
'is_permanent': 'on',
'site': '',
'redirect_link': 'http://www.test.com/ive-been-edited',
})
# Should not redirect to index
self.assertEqual(response.status_code, 200)
class TestRedirectsDeleteView(TestCase, WagtailTestUtils):
def setUp(self):
# Create a redirect to edit
self.redirect = models.Redirect(old_path='/test', redirect_link='http://www.test.com/')
self.redirect.save()
# Login
self.login()
def get(self, params={}, redirect_id=None):
return self.client.get(reverse('wagtailredirects:delete', args=(redirect_id or self.redirect.id, )), params)
def post(self, redirect_id=None):
return self.client.post(reverse(
'wagtailredirects:delete', args=(redirect_id or self.redirect.id, )
))
def test_simple(self):
response = self.get()
self.assertEqual(response.status_code, 200)
self.assertTemplateUsed(response, 'wagtailredirects/confirm_delete.html')
def test_nonexistant_redirect(self):
self.assertEqual(self.get(redirect_id=100000).status_code, 404)
def test_delete(self):
response = self.post()
# Should redirect back to index
self.assertRedirects(response, reverse('wagtailredirects:index'))
# Check that the redirect was deleted
redirects = models.Redirect.objects.filter(old_path='/test')
self.assertEqual(redirects.count(), 0)