addons-server/apps/amo/tests/test_views.py

383 строки
15 KiB
Python

# -*- coding: utf-8 -*-
from datetime import datetime
import json
import urllib
from django import test
from django.conf import settings
import commonware.log
from lxml import etree
import mock
from mock import patch
from nose.tools import eq_
from pyquery import PyQuery as pq
import amo.tests
from access import acl
from access.models import Group, GroupUser
from addons.models import Addon, AddonUser
from amo.helpers import locale_url, urlparams
from amo.pyquery_wrapper import PyQuery
from amo.tests import check_links
from amo.urlresolvers import reverse
from users.models import UserProfile
class Test403(amo.tests.TestCase):
fixtures = ['base/users']
def setUp(self):
assert self.client.login(username='regular@mozilla.com',
password='password')
def test_403_no_app(self):
response = self.client.get('/en-US/admin/')
eq_(response.status_code, 403)
self.assertTemplateUsed(response, 'amo/403.html')
def test_403_app(self):
response = self.client.get('/en-US/thunderbird/admin/', follow=True)
eq_(response.status_code, 403)
self.assertTemplateUsed(response, 'amo/403.html')
class Test404(amo.tests.TestCase):
def test_404_no_app(self):
"""Make sure a 404 without an app doesn't turn into a 500."""
# That could happen if helpers or templates expect APP to be defined.
url = reverse('amo.monitor')
response = self.client.get(url + 'nonsense')
eq_(response.status_code, 404)
self.assertTemplateUsed(response, 'amo/404.html')
def test_404_app_links(self):
response = self.client.get('/en-US/thunderbird/xxxxxxx')
eq_(response.status_code, 404)
self.assertTemplateUsed(response, 'amo/404.html')
links = pq(response.content)('[role=main] ul li a:not([href^=mailto])')
eq_(len(links), 4)
for link in links:
href = link.attrib['href']
assert href.startswith('/en-US/thunderbird'), href
class TestCommon(amo.tests.TestCase):
fixtures = ('base/users', 'base/global-stats', 'base/configs',
'base/addon_3615')
def setUp(self):
self.url = reverse('home')
# TODO: Remove when `submit-personas` flag is gone.
self.patcher = mock.patch('waffle.flag_is_active')
self.patcher.start().return_value = True
self.addCleanup(self.patcher.stop)
def login(self, user):
user = UserProfile.objects.get(email='%s@mozilla.com' % user)
self.client.login(username=user.email, password='password')
return user
@mock.patch.object(settings, 'READ_ONLY', False)
def test_balloons_no_readonly(self):
response = self.client.get('/en-US/firefox/')
doc = pq(response.content)
eq_(doc('#site-notice').length, 0)
eq_(doc('#site-nonfx').length, 1)
eq_(doc('#site-welcome').length, 1)
@mock.patch.object(settings, 'READ_ONLY', True)
def test_balloons_readonly(self):
response = self.client.get('/en-US/firefox/')
doc = pq(response.content)
eq_(doc('#site-notice').length, 1)
eq_(doc('#site-nonfx').length, 1)
eq_(doc('#site-welcome').length, 1)
@mock.patch.object(settings, 'READ_ONLY', False)
def test_thunderbird_balloons_no_readonly(self):
response = self.client.get('/en-US/thunderbird/')
eq_(response.status_code, 200)
doc = pq(response.content)
eq_(doc('#site-notice').length, 0)
@mock.patch.object(settings, 'READ_ONLY', True)
def test_thunderbird_balloons_readonly(self):
response = self.client.get('/en-US/thunderbird/')
doc = pq(response.content)
eq_(doc('#site-notice').length, 1)
eq_(doc('#site-nonfx').length, 0,
'This balloon should appear for Firefox only')
eq_(doc('#site-welcome').length, 1)
def test_tools_loggedout(self):
r = self.client.get(self.url, follow=True)
eq_(pq(r.content)('#aux-nav .tools').length, 0)
def test_tools_regular_user(self):
self.login('regular')
r = self.client.get(self.url, follow=True)
eq_(r.context['request'].amo_user.is_developer, False)
expected = [
('Tools', '#'),
('Submit a New Add-on', reverse('devhub.submit.1')),
('Submit a New Persona', reverse('devhub.personas.submit')),
('Developer Hub', reverse('devhub.index')),
]
check_links(expected, pq(r.content)('#aux-nav .tools a'))
def test_tools_developer(self):
# Make them a developer.
user = self.login('regular')
AddonUser.objects.create(user=user, addon=Addon.objects.all()[0])
group = Group.objects.create(name='Staff', rules='AdminTools:View')
GroupUser.objects.create(group=group, user=user)
r = self.client.get(self.url, follow=True)
eq_(r.context['request'].amo_user.is_developer, True)
expected = [
('Tools', '#'),
('Manage My Add-ons', reverse('devhub.addons')),
('Submit a New Add-on', reverse('devhub.submit.1')),
('Submit a New Persona', reverse('devhub.personas.submit')),
('Developer Hub', reverse('devhub.index')),
]
check_links(expected, pq(r.content)('#aux-nav .tools a'))
def test_tools_editor(self):
self.login('editor')
r = self.client.get(self.url, follow=True)
request = r.context['request']
eq_(request.amo_user.is_developer, False)
eq_(acl.action_allowed(request, 'Addons', 'Review'), True)
expected = [
('Tools', '#'),
('Submit a New Add-on', reverse('devhub.submit.1')),
('Submit a New Persona', reverse('devhub.personas.submit')),
('Developer Hub', reverse('devhub.index')),
('Editor Tools', reverse('editors.home')),
]
check_links(expected, pq(r.content)('#aux-nav .tools a'))
def test_tools_developer_and_editor(self):
# Make them a developer.
user = self.login('editor')
AddonUser.objects.create(user=user, addon=Addon.objects.all()[0])
r = self.client.get(self.url, follow=True)
request = r.context['request']
eq_(request.amo_user.is_developer, True)
eq_(acl.action_allowed(request, 'Addons', 'Review'), True)
expected = [
('Tools', '#'),
('Manage My Add-ons', reverse('devhub.addons')),
('Submit a New Add-on', reverse('devhub.submit.1')),
('Submit a New Persona', reverse('devhub.personas.submit')),
('Developer Hub', reverse('devhub.index')),
('Editor Tools', reverse('editors.home')),
]
check_links(expected, pq(r.content)('#aux-nav .tools a'))
def test_tools_admin(self):
self.login('admin')
r = self.client.get(self.url, follow=True)
request = r.context['request']
eq_(request.amo_user.is_developer, False)
eq_(acl.action_allowed(request, 'Addons', 'Review'), True)
eq_(acl.action_allowed(request, 'Localizer', '%'), True)
eq_(acl.action_allowed(request, 'Admin', '%'), True)
expected = [
('Tools', '#'),
('Submit a New Add-on', reverse('devhub.submit.1')),
('Submit a New Persona', reverse('devhub.personas.submit')),
('Developer Hub', reverse('devhub.index')),
('Editor Tools', reverse('editors.home')),
('Localizer Tools', '/localizers'),
('Admin Tools', reverse('zadmin.home')),
]
check_links(expected, pq(r.content)('#aux-nav .tools a'))
def test_tools_developer_and_admin(self):
# Make them a developer.
user = self.login('admin')
AddonUser.objects.create(user=user, addon=Addon.objects.all()[0])
r = self.client.get(self.url, follow=True)
request = r.context['request']
eq_(request.amo_user.is_developer, True)
eq_(acl.action_allowed(request, 'Addons', 'Review'), True)
eq_(acl.action_allowed(request, 'Localizer', '%'), True)
eq_(acl.action_allowed(request, 'Admin', '%'), True)
expected = [
('Tools', '#'),
('Manage My Add-ons', reverse('devhub.addons')),
('Submit a New Add-on', reverse('devhub.submit.1')),
('Submit a New Persona', reverse('devhub.personas.submit')),
('Developer Hub', reverse('devhub.index')),
('Editor Tools', reverse('editors.home')),
('Localizer Tools', '/localizers'),
('Admin Tools', reverse('zadmin.home')),
]
check_links(expected, pq(r.content)('#aux-nav .tools a'))
def test_heading(self):
def title_eq(url, alt, text):
response = self.client.get(url, follow=True)
doc = PyQuery(response.content)
eq_(alt, doc('.site-title img').attr('alt'))
eq_(text, doc('.site-title').text())
title_eq('/firefox', 'Firefox', 'Add-ons')
title_eq('/thunderbird', 'Thunderbird', 'Add-ons')
title_eq('/mobile', 'Mobile', 'Mobile Add-ons')
title_eq('/android', 'Android', 'Android Add-ons')
def test_xenophobia(self):
r = self.client.get(self.url, follow=True)
self.assertNotContains(r, 'show only English (US) add-ons')
def test_login_link(self):
r = self.client.get(self.url, follow=True)
doc = PyQuery(r.content)
next = urllib.urlencode({'to': '/en-US/firefox/'})
eq_('/en-US/firefox/users/login?%s' % next,
doc('.account.anonymous a')[1].attrib['href'])
class TestOtherStuff(amo.tests.TestCase):
# Tests that don't need fixtures but do need redis mocked.
def test_language_selector(self):
doc = pq(test.Client().get('/en-US/firefox/').content)
eq_(doc('form.languages option[selected]').attr('value'), 'en-us')
def test_language_selector_variables(self):
r = self.client.get('/en-US/firefox/?foo=fooval&bar=barval')
doc = pq(r.content)('form.languages')
eq_(doc('input[type=hidden][name=foo]').attr('value'), 'fooval')
eq_(doc('input[type=hidden][name=bar]').attr('value'), 'barval')
@patch.object(settings, 'KNOWN_PROXIES', ['127.0.0.1'])
def test_remote_addr(self):
"""Make sure we're setting REMOTE_ADDR from X_FORWARDED_FOR."""
client = test.Client()
# Send X-Forwarded-For as it shows up in a wsgi request.
client.get('/en-US/firefox/', follow=True,
HTTP_X_FORWARDED_FOR='1.1.1.1')
eq_(commonware.log.get_remote_addr(), '1.1.1.1')
def test_jsi18n_caching(self):
# The jsi18n catalog should be cached for a long time.
# Get the url from a real page so it includes the build id.
client = test.Client()
doc = pq(client.get('/', follow=True).content)
js_url = reverse('jsi18n')
url_with_build = doc('script[src^="%s"]' % js_url).attr('src')
response = client.get(url_with_build, follow=True)
fmt = '%a, %d %b %Y %H:%M:%S GMT'
expires = datetime.strptime(response['Expires'], fmt)
assert (expires - datetime.now()).days >= 365
def test_dictionaries_link(self):
doc = pq(test.Client().get('/', follow=True).content)
eq_(doc('#site-nav #more .more-lang a').attr('href'),
reverse('browse.language-tools'))
def test_personas_subnav(self):
doc = pq(self.client.get(reverse('home')).content)
base_url = reverse('browse.personas')
expected = [
('Personas', base_url),
('Most Popular', urlparams(base_url, sort='popular')),
('Top Rated', urlparams(base_url, sort='rating')),
('Newest', urlparams(base_url, sort='created')),
]
check_links(expected, doc('#site-nav #personas a'))
def test_mobile_link_firefox(self):
doc = pq(test.Client().get('/firefox', follow=True).content)
eq_(doc('#site-nav #more .more-mobile a').attr('href'),
locale_url(amo.MOBILE.short))
def test_mobile_link_nonfirefox(self):
for app in ('thunderbird', 'mobile'):
doc = pq(test.Client().get('/' + app, follow=True).content)
eq_(doc('#site-nav #more .more-mobile').length, 0)
def test_opensearch(self):
client = test.Client()
page = client.get('/en-US/firefox/opensearch.xml')
wanted = ('Content-Type', 'text/xml')
eq_(page._headers['content-type'], wanted)
doc = etree.fromstring(page.content)
e = doc.find("{http://a9.com/-/spec/opensearch/1.1/}ShortName")
eq_(e.text, "Firefox Add-ons")
def test_login_link(self):
# Test that the login link encodes parameters correctly.
r = test.Client().get('/?your=mom', follow=True)
doc = pq(r.content)
assert doc('.account.anonymous a')[1].attrib['href'].endswith(
'?to=%2Fen-US%2Ffirefox%2F%3Fyour%3Dmom'), ("Got %s" %
doc('.account.anonymous a')[1].attrib['href'])
r = test.Client().get(u'/ar/firefox/?q=འ')
doc = pq(r.content)
link = doc('.account.anonymous a')[1].attrib['href']
assert link.endswith('?to=%2Far%2Ffirefox%2F%3Fq%3D%25E0%25BD%25A0')
@mock.patch.object(settings, 'PFS_URL', 'https://pfs.mozilla.org/pfs.py')
def test_plugincheck_redirect(self):
r = test.Client().get('/services/pfs.php?'
'mimetype=application%2Fx-shockwave-flash&'
'appID={ec8030f7-c20a-464f-9b0e-13a3a9e97384}&'
'appVersion=20120215223356&'
'clientOS=Windows%20NT%205.1&'
'chromeLocale=en-US&appRelease=10.0.2')
self.assertEquals(r.status_code, 302)
self.assertEquals(r['Location'], ('https://pfs.mozilla.org/pfs.py?'
'mimetype=application%2Fx-shockwave-flash&'
'appID=%7Bec8030f7-c20a-464f-9b0e-13a3a9e97384%7D&'
'appVersion=20120215223356&'
'clientOS=Windows%20NT%205.1&'
'chromeLocale=en-US&appRelease=10.0.2'))
@mock.patch('amo.views.log_cef')
class TestCSP(amo.tests.TestCase):
def setUp(self):
self.url = reverse('amo.csp.report')
self.create_sample(name='csp-store-reports')
def test_get_document(self, log_cef):
eq_(self.client.get(self.url).status_code, 405)
def test_malformed(self, log_cef):
res = self.client.post(self.url, 'f', content_type='application/json')
eq_(res.status_code, 400)
def test_document_uri(self, log_cef):
url = 'http://foo.com'
self.client.post(self.url,
json.dumps({'csp-report': {'document-uri': url}}),
content_type='application/json')
eq_(log_cef.call_args[0][2]['PATH_INFO'], url)
def test_no_document_uri(self, log_cef):
self.client.post(self.url, json.dumps({'csp-report': {}}),
content_type='application/json')
eq_(log_cef.call_args[0][2]['PATH_INFO'], '/services/csp/report')