430 строки
16 KiB
Python
430 строки
16 KiB
Python
import base64
|
|
from datetime import datetime
|
|
from xml.dom import minidom
|
|
|
|
from django.conf import settings
|
|
from django.core.cache import cache
|
|
|
|
from nose.tools import eq_
|
|
|
|
import amo
|
|
import amo.tests
|
|
from amo.urlresolvers import reverse
|
|
from .models import (BlocklistApp, BlocklistCA, BlocklistDetail,
|
|
BlocklistItem, BlocklistGfx, BlocklistPlugin)
|
|
|
|
base_xml = """
|
|
<?xml version="1.0"?>
|
|
<blocklist xmlns="http://www.mozilla.org/2006/addons-blocklist">
|
|
</blocklist>
|
|
"""
|
|
|
|
|
|
class BlocklistTest(amo.tests.TestCase):
|
|
|
|
def setUp(self):
|
|
super(BlocklistTest, self).setUp()
|
|
self.fx4_url = reverse('blocklist', args=[3, amo.FIREFOX.guid, '4.0'])
|
|
self.fx2_url = reverse('blocklist', args=[2, amo.FIREFOX.guid, '2.0'])
|
|
self.mobile_url = reverse('blocklist', args=[2, amo.MOBILE.guid, '.9'])
|
|
cache.clear()
|
|
self.details = BlocklistDetail.objects.create()
|
|
|
|
def normalize(self, s):
|
|
return '\n'.join(x.strip() for x in s.split())
|
|
|
|
def eq_(self, x, y):
|
|
return eq_(self.normalize(x), self.normalize(y))
|
|
|
|
def dom(self, url):
|
|
r = self.client.get(url)
|
|
return minidom.parseString(r.content)
|
|
|
|
|
|
class BlocklistItemTest(BlocklistTest):
|
|
|
|
def setUp(self):
|
|
super(BlocklistItemTest, self).setUp()
|
|
self.item = BlocklistItem.objects.create(guid='guid@addon.com',
|
|
details=self.details)
|
|
self.app = BlocklistApp.objects.create(blitem=self.item,
|
|
guid=amo.FIREFOX.guid)
|
|
|
|
def stupid_unicode_test(self):
|
|
junk = u'\xc2\x80\x15\xc2\x80\xc3'
|
|
url = reverse('blocklist', args=[3, amo.FIREFOX.guid, junk])
|
|
# Just make sure it doesn't fail.
|
|
eq_(self.client.get(url).status_code, 200)
|
|
|
|
def test_content_type(self):
|
|
response = self.client.get(self.fx4_url)
|
|
eq_(response['Content-Type'], 'text/xml')
|
|
|
|
def test_empty_string_goes_null_on_save(self):
|
|
b = BlocklistItem(guid='guid', min='', max='', os='')
|
|
b.save()
|
|
assert b.min is None
|
|
assert b.max is None
|
|
assert b.os is None
|
|
|
|
def test_lastupdate(self):
|
|
def eq(a, b):
|
|
eq_(a, b.replace(microsecond=0))
|
|
|
|
def find_lastupdate():
|
|
bl = self.dom(self.fx4_url).getElementsByTagName('blocklist')[0]
|
|
t = int(bl.getAttribute('lastupdate')) / 1000
|
|
return datetime.fromtimestamp(t)
|
|
|
|
eq(find_lastupdate(), self.item.created)
|
|
|
|
self.item.save()
|
|
eq(find_lastupdate(), self.item.modified)
|
|
|
|
plugin = BlocklistPlugin.objects.create(guid=amo.FIREFOX.guid)
|
|
eq(find_lastupdate(), plugin.created)
|
|
plugin.save()
|
|
eq(find_lastupdate(), plugin.modified)
|
|
|
|
gfx = BlocklistGfx.objects.create(guid=amo.FIREFOX.guid)
|
|
eq(find_lastupdate(), gfx.created)
|
|
gfx.save()
|
|
eq(find_lastupdate(), gfx.modified)
|
|
|
|
assert (self.item.created != self.item.modified != plugin.created
|
|
!= plugin.modified != gfx.created != gfx.modified)
|
|
|
|
def test_no_items(self):
|
|
self.item.delete()
|
|
dom = self.dom(self.fx4_url)
|
|
children = dom.getElementsByTagName('blocklist')[0].childNodes
|
|
# There are only text nodes.
|
|
assert all(e.nodeType == 3 for e in children)
|
|
|
|
def test_existing_user_cookie(self):
|
|
self.client.cookies[settings.BLOCKLIST_COOKIE] = 'adfadf'
|
|
self.client.get(self.fx4_url)
|
|
eq_(self.client.cookies[settings.BLOCKLIST_COOKIE].value, 'adfadf')
|
|
|
|
def test_url_params(self):
|
|
eq_(self.client.get(self.fx4_url).status_code, 200)
|
|
eq_(self.client.get(self.fx2_url).status_code, 200)
|
|
# We ignore trailing url parameters.
|
|
eq_(self.client.get(self.fx4_url + 'other/junk/').status_code, 200)
|
|
|
|
def test_app_guid(self):
|
|
# There's one item for Firefox.
|
|
r = self.client.get(self.fx4_url)
|
|
eq_(r.status_code, 200)
|
|
eq_(len(r.context['items']), 1)
|
|
|
|
# There are no items for mobile.
|
|
r = self.client.get(self.mobile_url)
|
|
eq_(r.status_code, 200)
|
|
eq_(len(r.context['items']), 0)
|
|
|
|
# Without the app constraint we see the item.
|
|
self.app.delete()
|
|
r = self.client.get(self.mobile_url)
|
|
eq_(r.status_code, 200)
|
|
eq_(len(r.context['items']), 1)
|
|
|
|
def test_item_guid(self):
|
|
items = self.dom(self.fx4_url).getElementsByTagName('emItem')
|
|
eq_(len(items), 1)
|
|
eq_(items[0].getAttribute('id'), 'guid@addon.com')
|
|
|
|
def test_block_id(self):
|
|
item = self.dom(self.fx4_url).getElementsByTagName('emItem')[0]
|
|
eq_(item.getAttribute('blockID'), 'i' + str(self.details.id))
|
|
|
|
def test_item_os(self):
|
|
item = self.dom(self.fx4_url).getElementsByTagName('emItem')[0]
|
|
assert 'os' not in item.attributes.keys()
|
|
|
|
self.item.update(os='win,mac')
|
|
item = self.dom(self.fx4_url).getElementsByTagName('emItem')[0]
|
|
eq_(item.getAttribute('os'), 'win,mac')
|
|
|
|
def test_item_severity(self):
|
|
self.item.update(severity=2)
|
|
eq_(len(self.vr()), 1)
|
|
item = self.dom(self.fx4_url).getElementsByTagName('emItem')[0]
|
|
vrange = item.getElementsByTagName('versionRange')
|
|
eq_(vrange[0].getAttribute('severity'), '2')
|
|
|
|
def test_item_severity_zero(self):
|
|
# Don't show severity if severity==0.
|
|
self.item.update(severity=0, min='0.1')
|
|
eq_(len(self.vr()), 1)
|
|
item = self.dom(self.fx4_url).getElementsByTagName('emItem')[0]
|
|
vrange = item.getElementsByTagName('versionRange')
|
|
eq_(vrange[0].getAttribute('minVersion'), '0.1')
|
|
assert not vrange[0].hasAttribute('severity')
|
|
|
|
def vr(self):
|
|
item = self.dom(self.fx4_url).getElementsByTagName('emItem')[0]
|
|
return item.getElementsByTagName('versionRange')
|
|
|
|
def test_item_version_range(self):
|
|
self.item.update(min='0.1')
|
|
eq_(len(self.vr()), 1)
|
|
eq_(self.vr()[0].attributes.keys(), ['minVersion'])
|
|
eq_(self.vr()[0].getAttribute('minVersion'), '0.1')
|
|
|
|
self.item.update(max='0.2')
|
|
eq_(self.vr()[0].attributes.keys(), ['minVersion', 'maxVersion'])
|
|
eq_(self.vr()[0].getAttribute('minVersion'), '0.1')
|
|
eq_(self.vr()[0].getAttribute('maxVersion'), '0.2')
|
|
|
|
def test_item_multiple_version_range(self):
|
|
# There should be two <versionRange>s under one <emItem>.
|
|
self.item.update(min='0.1', max='0.2')
|
|
BlocklistItem.objects.create(guid=self.item.guid, severity=3)
|
|
|
|
item = self.dom(self.fx4_url).getElementsByTagName('emItem')
|
|
eq_(len(item), 1)
|
|
vr = item[0].getElementsByTagName('versionRange')
|
|
eq_(len(vr), 2)
|
|
eq_(vr[0].getAttribute('minVersion'), '0.1')
|
|
eq_(vr[0].getAttribute('maxVersion'), '0.2')
|
|
eq_(vr[1].getAttribute('severity'), '3')
|
|
|
|
def test_item_target_app(self):
|
|
app = self.app
|
|
self.app.delete()
|
|
self.item.update(severity=2)
|
|
version_range = self.vr()[0]
|
|
eq_(version_range.getElementsByTagName('targetApplication'), [])
|
|
|
|
app.save()
|
|
version_range = self.vr()[0]
|
|
target_app = version_range.getElementsByTagName('targetApplication')
|
|
eq_(len(target_app), 1)
|
|
eq_(target_app[0].getAttribute('id'), amo.FIREFOX.guid)
|
|
|
|
app.update(min='0.1', max='*')
|
|
version_range = self.vr()[0]
|
|
target_app = version_range.getElementsByTagName('targetApplication')
|
|
eq_(target_app[0].getAttribute('id'), amo.FIREFOX.guid)
|
|
tvr = target_app[0].getElementsByTagName('versionRange')
|
|
eq_(tvr[0].getAttribute('minVersion'), '0.1')
|
|
eq_(tvr[0].getAttribute('maxVersion'), '*')
|
|
|
|
def test_item_multiple_apps(self):
|
|
# Make sure all <targetApplication>s go under the same <versionRange>.
|
|
self.app.update(min='0.1', max='0.2')
|
|
BlocklistApp.objects.create(guid=amo.FIREFOX.guid, blitem=self.item,
|
|
min='3.0', max='3.1')
|
|
version_range = self.vr()[0]
|
|
apps = version_range.getElementsByTagName('targetApplication')
|
|
eq_(len(apps), 2)
|
|
eq_(apps[0].getAttribute('id'), amo.FIREFOX.guid)
|
|
vr = apps[0].getElementsByTagName('versionRange')[0]
|
|
eq_(vr.getAttribute('minVersion'), '0.1')
|
|
eq_(vr.getAttribute('maxVersion'), '0.2')
|
|
eq_(apps[1].getAttribute('id'), amo.FIREFOX.guid)
|
|
vr = apps[1].getElementsByTagName('versionRange')[0]
|
|
eq_(vr.getAttribute('minVersion'), '3.0')
|
|
eq_(vr.getAttribute('maxVersion'), '3.1')
|
|
|
|
def test_item_empty_version_range(self):
|
|
# No version_range without an app, min, max, or severity.
|
|
self.app.delete()
|
|
self.item.update(min=None, max=None, severity=None)
|
|
eq_(len(self.vr()), 0)
|
|
|
|
def test_item_empty_target_app(self):
|
|
# No empty <targetApplication>.
|
|
self.item.update(severity=1)
|
|
self.app.delete()
|
|
eq_(self.dom(self.fx4_url).getElementsByTagName('targetApplication'),
|
|
[])
|
|
|
|
def test_item_target_empty_version_range(self):
|
|
app = self.dom(self.fx4_url).getElementsByTagName('targetApplication')
|
|
eq_(app[0].getElementsByTagName('versionRange'), [])
|
|
|
|
|
|
class BlocklistPluginTest(BlocklistTest):
|
|
|
|
def setUp(self):
|
|
super(BlocklistPluginTest, self).setUp()
|
|
self.plugin = BlocklistPlugin.objects.create(guid=amo.FIREFOX.guid,
|
|
details=self.details)
|
|
|
|
def test_no_plugins(self):
|
|
dom = BlocklistTest.dom(self, self.mobile_url)
|
|
children = dom.getElementsByTagName('blocklist')[0].childNodes
|
|
# There are only text nodes.
|
|
assert all(e.nodeType == 3 for e in children)
|
|
|
|
def dom(self, url=None):
|
|
url = url or self.fx4_url
|
|
r = self.client.get(url)
|
|
d = minidom.parseString(r.content)
|
|
return d.getElementsByTagName('pluginItem')[0]
|
|
|
|
def test_plugin_empty(self):
|
|
eq_(self.dom().attributes.keys(), ['blockID'])
|
|
eq_(self.dom().getElementsByTagName('match'), [])
|
|
eq_(self.dom().getElementsByTagName('versionRange'), [])
|
|
|
|
def test_block_id(self):
|
|
item = self.dom(self.fx4_url)
|
|
eq_(item.getAttribute('blockID'), 'p' + str(self.details.id))
|
|
|
|
def test_plugin_os(self):
|
|
self.plugin.update(os='win')
|
|
eq_(sorted(self.dom().attributes.keys()), ['blockID', 'os'])
|
|
eq_(self.dom().getAttribute('os'), 'win')
|
|
|
|
def test_plugin_xpcomabi(self):
|
|
self.plugin.update(xpcomabi='win')
|
|
eq_(sorted(self.dom().attributes.keys()), ['blockID', 'xpcomabi'])
|
|
eq_(self.dom().getAttribute('xpcomabi'), 'win')
|
|
|
|
def test_plugin_name(self):
|
|
self.plugin.update(name='flash')
|
|
match = self.dom().getElementsByTagName('match')
|
|
eq_(len(match), 1)
|
|
eq_(dict(match[0].attributes.items()),
|
|
{'name': 'name', 'exp': 'flash'})
|
|
|
|
def test_plugin_description(self):
|
|
self.plugin.update(description='flash')
|
|
match = self.dom().getElementsByTagName('match')
|
|
eq_(len(match), 1)
|
|
eq_(dict(match[0].attributes.items()),
|
|
{'name': 'description', 'exp': 'flash'})
|
|
|
|
def test_plugin_filename(self):
|
|
self.plugin.update(filename='flash')
|
|
match = self.dom().getElementsByTagName('match')
|
|
eq_(len(match), 1)
|
|
eq_(dict(match[0].attributes.items()),
|
|
{'name': 'filename', 'exp': 'flash'})
|
|
|
|
def test_plugin_severity(self):
|
|
self.plugin.update(severity=2)
|
|
v = self.dom().getElementsByTagName('versionRange')[0]
|
|
eq_(v.getAttribute('severity'), '2')
|
|
|
|
def test_plugin_no_target_app(self):
|
|
self.plugin.update(guid=None, severity=1, min='1', max='2')
|
|
vr = self.dom().getElementsByTagName('versionRange')[0]
|
|
eq_(vr.getElementsByTagName('targetApplication'), [],
|
|
'There should not be a <targetApplication> if there was no app')
|
|
eq_(vr.getAttribute('severity'), '1')
|
|
eq_(vr.getAttribute('minVersion'), '1')
|
|
eq_(vr.getAttribute('maxVersion'), '2')
|
|
|
|
def test_plugin_with_target_app(self):
|
|
self.plugin.update(guid=amo.FIREFOX.guid, severity=1, min='1', max='2')
|
|
vr = self.dom().getElementsByTagName('versionRange')[0]
|
|
eq_(vr.getAttribute('severity'), '1')
|
|
|
|
app = vr.getElementsByTagName('targetApplication')[0]
|
|
eq_(app.getAttribute('id'), amo.FIREFOX.guid)
|
|
|
|
vr = app.getElementsByTagName('versionRange')[0]
|
|
eq_(vr.getAttribute('minVersion'), '1')
|
|
eq_(vr.getAttribute('maxVersion'), '2')
|
|
|
|
def test_plugin_with_severity_only(self):
|
|
self.plugin.update(guid=None, severity=1)
|
|
vr = self.dom().getElementsByTagName('versionRange')[0]
|
|
eq_(vr.getAttribute('severity'), '1')
|
|
eq_(vr.getAttribute('minVersion'), '')
|
|
eq_(vr.getAttribute('maxVersion'), '')
|
|
|
|
eq_(vr.getElementsByTagName('targetApplication'), [],
|
|
'There should not be a <targetApplication> if there was no app')
|
|
|
|
def test_plugin_apiver_lt_3(self):
|
|
self.plugin.update(severity='2')
|
|
# No min & max so the app matches.
|
|
e = self.dom(self.fx2_url).getElementsByTagName('versionRange')[0]
|
|
eq_(e.getAttribute('severity'), '2')
|
|
eq_(e.getElementsByTagName('targetApplication'), [])
|
|
|
|
# The app version is not in range.
|
|
self.plugin.update(min='3.0', max='4.0')
|
|
self.assertRaises(IndexError, self.dom, self.fx2_url)
|
|
|
|
# The app is back in range.
|
|
self.plugin.update(min='1.1')
|
|
e = self.dom(self.fx2_url).getElementsByTagName('versionRange')[0]
|
|
eq_(e.getAttribute('severity'), '2')
|
|
eq_(e.getElementsByTagName('targetApplication'), [])
|
|
|
|
|
|
class BlocklistGfxTest(BlocklistTest):
|
|
|
|
def setUp(self):
|
|
super(BlocklistGfxTest, self).setUp()
|
|
self.gfx = BlocklistGfx.objects.create(
|
|
guid=amo.FIREFOX.guid, os='os', vendor='vendor', devices='x y z',
|
|
feature='feature', feature_status='status', details=self.details,
|
|
driver_version='version', driver_version_comparator='compare')
|
|
|
|
def test_no_gfx(self):
|
|
dom = self.dom(self.mobile_url)
|
|
children = dom.getElementsByTagName('blocklist')[0].childNodes
|
|
# There are only text nodes.
|
|
assert all(e.nodeType == 3 for e in children)
|
|
|
|
def test_gfx(self):
|
|
r = self.client.get(self.fx4_url)
|
|
dom = minidom.parseString(r.content)
|
|
gfx = dom.getElementsByTagName('gfxBlacklistEntry')[0]
|
|
find = lambda e: gfx.getElementsByTagName(e)[0].childNodes[0].wholeText
|
|
eq_(find('os'), self.gfx.os)
|
|
eq_(find('feature'), self.gfx.feature)
|
|
eq_(find('vendor'), self.gfx.vendor)
|
|
eq_(find('featureStatus'), self.gfx.feature_status)
|
|
eq_(find('driverVersion'), self.gfx.driver_version)
|
|
eq_(find('driverVersionComparator'),
|
|
self.gfx.driver_version_comparator)
|
|
devices = gfx.getElementsByTagName('devices')[0]
|
|
for device, val in zip(devices.getElementsByTagName('device'),
|
|
self.gfx.devices.split(' ')):
|
|
eq_(device.childNodes[0].wholeText, val)
|
|
|
|
def test_empty_devices(self):
|
|
self.gfx.devices = None
|
|
self.gfx.save()
|
|
r = self.client.get(self.fx4_url)
|
|
self.assertNotContains(r, '<devices>')
|
|
|
|
def test_no_empty_nodes(self):
|
|
self.gfx.update(os=None, vendor=None, devices=None,
|
|
feature=None, feature_status=None,
|
|
driver_version=None, driver_version_comparator=None)
|
|
r = self.client.get(self.fx4_url)
|
|
self.assertNotContains(r, '<os>')
|
|
self.assertNotContains(r, '<vendor>')
|
|
self.assertNotContains(r, '<devices>')
|
|
self.assertNotContains(r, '<feature>')
|
|
self.assertNotContains(r, '<featureStatus>')
|
|
self.assertNotContains(r, '<driverVersion>')
|
|
self.assertNotContains(r, '<driverVersionComparator>')
|
|
|
|
def test_block_id(self):
|
|
item = (self.dom(self.fx4_url)
|
|
.getElementsByTagName('gfxBlacklistEntry')[0])
|
|
eq_(item.getAttribute('blockID'), 'g' + str(self.details.id))
|
|
|
|
|
|
class BlocklistCATest(BlocklistTest):
|
|
|
|
def setUp(self):
|
|
super(BlocklistCATest, self).setUp()
|
|
self.ca = BlocklistCA.objects.create(data='999')
|
|
|
|
def test_ca(self):
|
|
r = self.client.get(self.fx4_url)
|
|
dom = minidom.parseString(r.content)
|
|
ca = dom.getElementsByTagName('caBlocklistEntry')[0]
|
|
eq_(base64.b64decode(ca.childNodes[0].toxml()), self.ca.data)
|