ignore version info for non-selected apps - add-on packager
This commit is contained in:
Родитель
4f119a1b46
Коммит
4f688a52c3
|
@ -8,11 +8,13 @@ import time
|
|||
|
||||
from django import forms
|
||||
from django.conf import settings
|
||||
from django.forms.fields import Field
|
||||
from django.test.client import Client
|
||||
from django.utils import translation
|
||||
|
||||
import elasticutils
|
||||
import nose
|
||||
from nose.tools import eq_
|
||||
import test_utils
|
||||
from redisutils import mock_redis, reset_redis
|
||||
|
||||
|
@ -61,6 +63,10 @@ def initial(form):
|
|||
return data
|
||||
|
||||
|
||||
def assert_required(error_msg):
|
||||
eq_(error_msg, unicode(Field.default_error_messages['required']))
|
||||
|
||||
|
||||
class RedisTest(object):
|
||||
"""Mixin for when you need to mock redis for testing."""
|
||||
|
||||
|
|
|
@ -22,6 +22,7 @@ from django.core.serializers import json
|
|||
from django.core.validators import ValidationError, validate_slug
|
||||
from django.core.mail import send_mail as django_send_mail
|
||||
from django.db.models.sql.datastructures import EmptyResultSet
|
||||
from django.forms.fields import Field
|
||||
from django.template import Context, loader
|
||||
from django.utils.translation import trans_real
|
||||
from django.utils.functional import Promise
|
||||
|
@ -293,6 +294,10 @@ def slug_validator(s, ok=SLUG_OK, lower=True):
|
|||
code=validate_slug.code)
|
||||
|
||||
|
||||
def raise_required():
|
||||
raise ValidationError(Field.default_error_messages['required'])
|
||||
|
||||
|
||||
def clear_messages(request):
|
||||
"""
|
||||
Clear any messages out of the messages framework for the authenticated
|
||||
|
|
|
@ -5,6 +5,7 @@ import socket
|
|||
from django import forms
|
||||
from django.conf import settings
|
||||
from django.db.models import Q
|
||||
from django.forms.fields import Field
|
||||
from django.forms.models import modelformset_factory
|
||||
from django.forms.formsets import formset_factory, BaseFormSet
|
||||
from django.utils.safestring import mark_safe
|
||||
|
@ -21,7 +22,7 @@ from addons.models import (Addon, AddonDependency, AddonUpsell, AddonUser,
|
|||
BlacklistedSlug, Charity, Preview)
|
||||
from amo.forms import AMOModelForm
|
||||
from amo.urlresolvers import reverse
|
||||
from amo.utils import slug_validator
|
||||
from amo.utils import raise_required, slug_validator
|
||||
|
||||
from amo.widgets import EmailWidget
|
||||
from applications.models import Application, AppVersion
|
||||
|
@ -763,10 +764,10 @@ class PackagerBasicForm(forms.Form):
|
|||
class PackagerCompatForm(forms.Form):
|
||||
enabled = forms.BooleanField(required=False)
|
||||
min_ver = forms.ModelChoiceField(AppVersion.objects.none(),
|
||||
empty_label=None,
|
||||
empty_label=None, required=False,
|
||||
label=_lazy(u'Minimum'))
|
||||
max_ver = forms.ModelChoiceField(AppVersion.objects.none(),
|
||||
empty_label=None,
|
||||
empty_label=None, required=False,
|
||||
label=_lazy(u'Maximum'))
|
||||
|
||||
def __init__(self, *args, **kwargs):
|
||||
|
@ -784,33 +785,43 @@ class PackagerCompatForm(forms.Form):
|
|||
self.fields['min_ver'].queryset = qs.filter(~Q(version__contains='*'))
|
||||
self.fields['max_ver'].queryset = qs.all()
|
||||
|
||||
def clean_min_ver(self):
|
||||
if self.cleaned_data['enabled'] and not self.cleaned_data['min_ver']:
|
||||
raise_required()
|
||||
return self.cleaned_data['min_ver']
|
||||
|
||||
def clean_max_ver(self):
|
||||
if self.cleaned_data['enabled'] and not self.cleaned_data['max_ver']:
|
||||
raise_required()
|
||||
return self.cleaned_data['max_ver']
|
||||
|
||||
def clean(self):
|
||||
if self.errors:
|
||||
return
|
||||
|
||||
data = self.cleaned_data
|
||||
if not data['enabled']:
|
||||
return data
|
||||
|
||||
min_ver = data['min_ver']
|
||||
max_ver = data['max_ver']
|
||||
if not (min_ver and max_ver):
|
||||
raise forms.ValidationError(
|
||||
_('Invalid version range.'))
|
||||
if data['enabled']:
|
||||
min_ver = data['min_ver']
|
||||
max_ver = data['max_ver']
|
||||
if not (min_ver and max_ver):
|
||||
raise forms.ValidationError(_('Invalid version range.'))
|
||||
|
||||
if min_ver.version_int > max_ver.version_int:
|
||||
raise forms.ValidationError(
|
||||
if min_ver.version_int > max_ver.version_int:
|
||||
raise forms.ValidationError(
|
||||
_('Min version must be less than Max version.'))
|
||||
|
||||
# Pass back the app name and GUID.
|
||||
data['min_ver'] = str(min_ver)
|
||||
data['max_ver'] = str(max_ver)
|
||||
data['name'] = self.app.pretty
|
||||
data['guid'] = self.app.guid
|
||||
# Pass back the app name and GUID.
|
||||
data['min_ver'] = str(min_ver)
|
||||
data['max_ver'] = str(max_ver)
|
||||
data['name'] = self.app.pretty
|
||||
data['guid'] = self.app.guid
|
||||
|
||||
return data
|
||||
|
||||
|
||||
class PackagerCompatBaseFormSet(BaseFormSet):
|
||||
|
||||
def __init__(self, *args, **kw):
|
||||
super(PackagerCompatBaseFormSet, self).__init__(*args, **kw)
|
||||
self.initial = [{'application': a} for a in amo.APP_USAGE]
|
||||
|
@ -819,14 +830,15 @@ class PackagerCompatBaseFormSet(BaseFormSet):
|
|||
def clean(self):
|
||||
if any(self.errors):
|
||||
return
|
||||
|
||||
if not any(cf.cleaned_data.get('enabled') for cf in self.forms):
|
||||
if (not self.forms or not
|
||||
any(f.cleaned_data.get('enabled') for f in self.forms)):
|
||||
raise forms.ValidationError(
|
||||
_('At least one target application must be selected.'))
|
||||
return self.cleaned_data
|
||||
|
||||
|
||||
PackagerCompatFormSet = formset_factory(PackagerCompatForm,
|
||||
formset=PackagerCompatBaseFormSet,
|
||||
extra=0)
|
||||
formset=PackagerCompatBaseFormSet, extra=0)
|
||||
|
||||
|
||||
class PackagerFeaturesForm(forms.Form):
|
||||
|
@ -958,12 +970,12 @@ class PremiumForm(happyforms.Form):
|
|||
|
||||
def clean_text(self):
|
||||
if self.cleaned_data['do_upsell'] and not self.cleaned_data['text']:
|
||||
raise forms.ValidationError(_('This field is required.'))
|
||||
raise_required()
|
||||
return self.cleaned_data['text']
|
||||
|
||||
def clean_free(self):
|
||||
if self.cleaned_data['do_upsell'] and not self.cleaned_data['free']:
|
||||
raise forms.ValidationError(_('This field is required.'))
|
||||
raise_required()
|
||||
return self.cleaned_data['free']
|
||||
|
||||
def save(self):
|
||||
|
|
|
@ -7,7 +7,7 @@ from nose.tools import eq_
|
|||
from pyquery import PyQuery as pq
|
||||
|
||||
import amo.tests
|
||||
from amo.tests import formset, initial
|
||||
from amo.tests import assert_required, formset, initial
|
||||
from amo.urlresolvers import reverse
|
||||
from addons.models import BlacklistedSlug
|
||||
from devhub.views import packager_path
|
||||
|
@ -20,35 +20,13 @@ class TestAddOnPackager(amo.tests.TestCase):
|
|||
def setUp(self):
|
||||
assert self.client.login(username='regular@mozilla.com',
|
||||
password='password')
|
||||
self.package_addon = reverse('devhub.package_addon')
|
||||
self.url = reverse('devhub.package_addon')
|
||||
|
||||
ctx = self.client.get(self.package_addon).context['compat_forms']
|
||||
ctx = self.client.get(self.url).context['compat_forms']
|
||||
self.compat_form = initial(ctx.initial_forms[1])
|
||||
|
||||
def test_has_versions(self):
|
||||
"""Test that versions are listed in targetApplication fields."""
|
||||
r = self.client.get(self.package_addon)
|
||||
eq_(r.status_code, 200)
|
||||
|
||||
doc = pq(r.content)
|
||||
# Assert that the first dropdown (Firefox) has at least thirty items.
|
||||
assert len(doc('.supported-apps select').children()) > 30
|
||||
|
||||
def test_no_mozilla(self):
|
||||
"""
|
||||
Test that the Mozilla browser is not represented in the
|
||||
targetApplication list.
|
||||
"""
|
||||
r = self.client.get(self.package_addon)
|
||||
eq_(r.status_code, 200)
|
||||
|
||||
doc = pq(r.content)
|
||||
for label in doc('.supported-apps label.app'):
|
||||
assert pq(label).text() != 'Mozilla'
|
||||
|
||||
def _form_data(self, data=None, compat_form=True):
|
||||
def _form_data(self, data={}, compat_forms=None):
|
||||
"""Build the initial data set for the form."""
|
||||
|
||||
initial_data = {'author_name': 'author',
|
||||
'contributors': '',
|
||||
'description': '',
|
||||
|
@ -56,14 +34,29 @@ class TestAddOnPackager(amo.tests.TestCase):
|
|||
'package_name': 'name',
|
||||
'id': 'foo@bar.com',
|
||||
'version': '1.2.3'}
|
||||
|
||||
if compat_form:
|
||||
initial_data.update(formset(self.compat_form))
|
||||
|
||||
if not compat_forms:
|
||||
compat_forms = [self.compat_form]
|
||||
initial_data.update(formset(*compat_forms))
|
||||
if data:
|
||||
initial_data.update(data)
|
||||
return initial_data
|
||||
|
||||
def test_required_login(self):
|
||||
self.client.logout()
|
||||
r = self.client.get(self.url)
|
||||
eq_(r.status_code, 302)
|
||||
|
||||
def test_form_initial(self):
|
||||
"""Ensure that the initial forms for each application are present."""
|
||||
r = self.client.get(self.url)
|
||||
eq_(r.status_code, 200)
|
||||
rows = pq(r.content)('.supported-apps li.row')
|
||||
classes = [a.short for a in amo.APP_USAGE]
|
||||
eq_(rows.length, len(classes))
|
||||
for app_class, label in zip(classes, rows('label.app')):
|
||||
assert pq(label).hasClass(app_class), (
|
||||
'Label for application %r not found' % app_class)
|
||||
|
||||
def test_validate_pass(self):
|
||||
"""
|
||||
Test that a proper set of data will pass validation and pass through
|
||||
|
@ -72,47 +65,43 @@ class TestAddOnPackager(amo.tests.TestCase):
|
|||
self.compat_form['enabled'] = 'on'
|
||||
self.compat_form['min_ver'] = '86'
|
||||
self.compat_form['max_ver'] = '114'
|
||||
r = self.client.post(self.package_addon, self._form_data(),
|
||||
follow=True)
|
||||
r = self.client.post(self.url, self._form_data(), follow=True)
|
||||
eq_(r.status_code, 200)
|
||||
eq_(pq(pq(r.content)('h3')[0]).text(), 'Add-on packaged successfully!')
|
||||
|
||||
def test_validate_name(self):
|
||||
"""Test that the add-on name is properly validated."""
|
||||
r = self.client.post(self.package_addon,
|
||||
self._form_data({'name': 'Mozilla App'}))
|
||||
r = self.client.post(self.url, self._form_data({'name': 'Mozilla <3'}))
|
||||
self.assertFormError(
|
||||
r, 'basic_form', 'name',
|
||||
'Add-on names should not contain Mozilla trademarks.')
|
||||
|
||||
def test_validate_package_name_required(self):
|
||||
r = self.client.post(self.package_addon,
|
||||
self._form_data({'package_name': ''}))
|
||||
r = self.client.post(self.url, self._form_data({'package_name': ''}))
|
||||
self.assertFormError(r, 'basic_form', 'package_name',
|
||||
'This field is required.')
|
||||
|
||||
def test_validate_package_name_format(self):
|
||||
r = self.client.post(self.package_addon,
|
||||
r = self.client.post(self.url,
|
||||
self._form_data({'package_name': 'addon name'}))
|
||||
self.assertFormError(r, 'basic_form', 'package_name',
|
||||
validate_slug.message)
|
||||
|
||||
def test_validate_package_name_taken(self):
|
||||
r = self.client.post(self.package_addon,
|
||||
r = self.client.post(self.url,
|
||||
self._form_data({'package_name': 'a3615'}))
|
||||
self.assertFormError(r, 'basic_form', 'package_name',
|
||||
'This slug is already in use.')
|
||||
|
||||
def test_validate_package_name_blacklisted(self):
|
||||
BlacklistedSlug.objects.create(name='slap_tickle')
|
||||
r = self.client.post(self.package_addon,
|
||||
r = self.client.post(self.url,
|
||||
self._form_data({'package_name': 'slap_tickle'}))
|
||||
self.assertFormError(r, 'basic_form', 'package_name',
|
||||
'The slug cannot be: slap_tickle.')
|
||||
|
||||
def test_validate_version(self):
|
||||
"""Test that the add-on version is properly validated."""
|
||||
r = self.client.post(self.package_addon,
|
||||
r = self.client.post(self.url,
|
||||
self._form_data({'version': 'invalid version'}))
|
||||
self.assertFormError(
|
||||
r, 'basic_form', 'version',
|
||||
|
@ -120,33 +109,34 @@ class TestAddOnPackager(amo.tests.TestCase):
|
|||
|
||||
def test_validate_id(self):
|
||||
"""Test that the add-on id is properly validated."""
|
||||
r = self.client.post(self.package_addon,
|
||||
self._form_data({'id': 'invalid id'}))
|
||||
r = self.client.post(self.url, self._form_data({'id': 'invalid id'}))
|
||||
self.assertFormError(
|
||||
r, 'basic_form', 'id',
|
||||
'The add-on ID must be a UUID string or an email address.')
|
||||
|
||||
def test_validate_version_enabled(self):
|
||||
"""Test that at least one version must be enabled."""
|
||||
# Nothing needs to be done; no apps are enabled by default.
|
||||
r = self.client.post(self.package_addon, self._form_data())
|
||||
assert not r.context['compat_forms'].is_valid()
|
||||
def test_app_required(self):
|
||||
"""Ensure that at least one target application is required."""
|
||||
self.compat_form = {}
|
||||
r = self.client.post(self.url, self._form_data())
|
||||
eq_(r.context['compat_forms'].non_form_errors(),
|
||||
['At least one target application must be selected.'])
|
||||
|
||||
def test_enabled_apps_version_required(self):
|
||||
"""Min/Max Version fields should be required for enabled apps."""
|
||||
forms = [self.compat_form, {'enabled': 'on'}]
|
||||
r = self.client.post(self.url, self._form_data(compat_forms=forms))
|
||||
assert_required(r.context['compat_forms'].errors[1]['min_ver'][0])
|
||||
assert_required(r.context['compat_forms'].errors[1]['max_ver'][0])
|
||||
|
||||
def test_validate_version_order(self):
|
||||
"""Test that the min version is lte the max version."""
|
||||
self.compat_form['enabled'] = 'on'
|
||||
self.compat_form['min_ver'] = '114'
|
||||
self.compat_form['max_ver'] = '86'
|
||||
r = self.client.post(self.package_addon,
|
||||
self._form_data())
|
||||
r = self.client.post(self.url, self._form_data())
|
||||
eq_(r.context['compat_forms'].errors[0]['__all__'][0],
|
||||
'Min version must be less than Max version.')
|
||||
|
||||
def test_required_login(self):
|
||||
self.client.logout()
|
||||
r = self.client.get(self.package_addon)
|
||||
eq_(r.status_code, 302)
|
||||
|
||||
|
||||
class TestPackagerJSON(amo.tests.TestCase):
|
||||
fixtures = ['base/apps', 'base/users', 'base/appversion']
|
||||
|
|
Загрузка…
Ссылка в новой задаче