Fix remaining Django 1.9 test failures

This patch gets Horizon to a passing state in the Django 1.9 tests

Co-Authored-By: Itxaka <iserrano@redhat.com>
Co-Authored-By: Timur Sufiev <tsufiev@mirantis.com>
Change-Id: Icbc1a3c039de658faa9fba4a2cdd5027345fe94d
Partially-Implements: blueprint drop-dj17
This commit is contained in:
Rob Cresswell 2016-02-11 14:45:32 +00:00 committed by Timur Sufiev
parent ac63c15c94
commit fd92d8ec59
21 changed files with 256 additions and 94 deletions

View File

@ -41,7 +41,7 @@ class SelfHandlingForm(SelfHandlingMixin, forms.Form):
wish for API errors to appear as errors on the form rather than wish for API errors to appear as errors on the form rather than
using the messages framework. using the messages framework.
""" """
self._errors[NON_FIELD_ERRORS] = self.error_class([message]) self.add_error(NON_FIELD_ERRORS, message)
def set_warning(self, message): def set_warning(self, message):
"""Sets a warning on the form. """Sets a warning on the form.

View File

@ -133,8 +133,7 @@ class ModalFormView(ModalBackdropMixin, ModalFormMixin, views.HorizonFormView):
cancel_label = _("Cancel") cancel_label = _("Cancel")
cancel_url = None cancel_url = None
def get_context_data(self, **kwargs): def _populate_context(self, context):
context = super(ModalFormView, self).get_context_data(**kwargs)
context['modal_id'] = self.modal_id context['modal_id'] = self.modal_id
context['modal_header'] = self.modal_header context['modal_header'] = self.modal_header
context['form_id'] = self.form_id context['form_id'] = self.form_id
@ -144,6 +143,11 @@ class ModalFormView(ModalBackdropMixin, ModalFormMixin, views.HorizonFormView):
context['cancel_url'] = self.get_cancel_url() context['cancel_url'] = self.get_cancel_url()
return context return context
def get_context_data(self, **kwargs):
context = super(ModalFormView, self).get_context_data(**kwargs)
context = self._populate_context(context)
return context
def get_cancel_url(self): def get_cancel_url(self):
return self.cancel_url or self.success_url return self.cancel_url or self.success_url
@ -165,6 +169,12 @@ class ModalFormView(ModalBackdropMixin, ModalFormMixin, views.HorizonFormView):
"""Returns an instance of the form to be used in this view.""" """Returns an instance of the form to be used in this view."""
return form_class(self.request, **self.get_form_kwargs()) return form_class(self.request, **self.get_form_kwargs())
def form_invalid(self, form):
context = super(ModalFormView, self).get_context_data()
context = self._populate_context(context)
context['form'] = form
return self.render_to_response(context)
def form_valid(self, form): def form_valid(self, form):
try: try:
handled = form.handle(self.request, form.cleaned_data) handled = form.handle(self.request, form.cleaned_data)

View File

@ -59,7 +59,8 @@ INSTALLED_APPS = (
'horizon', 'horizon',
'horizon.test', 'horizon.test',
'horizon.test.test_dashboards.cats', 'horizon.test.test_dashboards.cats',
'horizon.test.test_dashboards.dogs' 'horizon.test.test_dashboards.dogs',
'openstack_auth'
) )
MIDDLEWARE_CLASSES = ( MIDDLEWARE_CLASSES = (

View File

@ -17,6 +17,7 @@
# License for the specific language governing permissions and limitations # License for the specific language governing permissions and limitations
# under the License. # under the License.
import django
from django.conf import settings from django.conf import settings
from django.contrib.auth.models import User # noqa from django.contrib.auth.models import User # noqa
from django.core.exceptions import ImproperlyConfigured # noqa from django.core.exceptions import ImproperlyConfigured # noqa
@ -308,7 +309,10 @@ class HorizonTests(BaseHorizonTests):
self.client.logout() self.client.logout()
resp = self.client.get(url) resp = self.client.get(url)
self.assertRedirects(resp, redirect_url) if django.VERSION >= (1, 9):
self.assertRedirects(resp, settings.TESTSERVER + redirect_url)
else:
self.assertRedirects(resp, redirect_url)
# Set SSL settings for test server # Set SSL settings for test server
settings.SECURE_PROXY_SSL_HEADER = ('HTTP_X_FORWARDED_PROTOCOL', settings.SECURE_PROXY_SSL_HEADER = ('HTTP_X_FORWARDED_PROTOCOL',

View File

@ -27,6 +27,8 @@ class FormMixinTests(test.TestCase):
view.args = args view.args = args
view.kwargs = kwargs view.kwargs = kwargs
view.template_name = 'test_template' view.template_name = 'test_template'
# Note(Itxaka): ModalFormView requires a form_class to behave properly
view.form_class = TestForm
return view return view
def test_modal_form_mixin_hide_true_if_ajax(self): def test_modal_form_mixin_hide_true_if_ajax(self):
@ -80,7 +82,9 @@ class FormErrorTests(test.TestCase):
def setUp(self): def setUp(self):
super(FormErrorTests, self).setUp() super(FormErrorTests, self).setUp()
self.form = TestForm(self.request) # Note(Itxaka): We pass data to the form so its bound and has the
# proper cleaned_data fields
self.form = TestForm(self.request, data={'fake': 'data'})
def _render_form(self): def _render_form(self):
return shortcuts.render(self.request, self.template, return shortcuts.render(self.request, self.template,

View File

@ -13,8 +13,8 @@
# License for the specific language governing permissions and limitations # License for the specific language governing permissions and limitations
# under the License. # under the License.
import django
from django.conf import settings from django.conf import settings
from django.http import HttpResponseRedirect # noqa from django.http import HttpResponseRedirect # noqa
from django.utils import timezone from django.utils import timezone
@ -41,7 +41,10 @@ class MiddlewareTests(test.TestCase):
resp = mw.process_exception(request, exceptions.NotAuthorized()) resp = mw.process_exception(request, exceptions.NotAuthorized())
resp.client = self.client resp.client = self.client
self.assertRedirects(resp, url) if django.VERSION >= (1, 9):
self.assertRedirects(resp, settings.TESTSERVER + url)
else:
self.assertRedirects(resp, url)
def test_process_response_redirect_on_ajax_request(self): def test_process_response_redirect_on_ajax_request(self):
url = settings.LOGIN_URL url = settings.LOGIN_URL

View File

@ -387,8 +387,9 @@ class NetworkTests(test.BaseAdminViewTests):
tenant_id = self.tenants.first().id tenant_id = self.tenants.first().id
network = self.networks.first() network = self.networks.first()
extensions = self.api_extensions.list() extensions = self.api_extensions.list()
api.keystone.tenant_list(IsA(http.HttpRequest)).AndReturn([tenants, api.keystone.tenant_list(
False]) IsA(http.HttpRequest)
).MultipleTimes().AndReturn([tenants, False])
api.neutron.list_extensions( api.neutron.list_extensions(
IsA(http.HttpRequest)).AndReturn(extensions) IsA(http.HttpRequest)).AndReturn(extensions)
self.mox.ReplayAll() self.mox.ReplayAll()
@ -414,8 +415,11 @@ class NetworkTests(test.BaseAdminViewTests):
tenant_id = self.tenants.first().id tenant_id = self.tenants.first().id
network = self.networks.first() network = self.networks.first()
extensions = self.api_extensions.list() extensions = self.api_extensions.list()
api.keystone.tenant_list(IsA(http.HttpRequest)).AndReturn([tenants,
False]) api.keystone.tenant_list(
IsA(http.HttpRequest)
).MultipleTimes().AndReturn([tenants, False])
api.neutron.list_extensions( api.neutron.list_extensions(
IsA(http.HttpRequest)).AndReturn(extensions) IsA(http.HttpRequest)).AndReturn(extensions)
self.mox.ReplayAll() self.mox.ReplayAll()
@ -444,8 +448,10 @@ class NetworkTests(test.BaseAdminViewTests):
tenant_id = self.tenants.first().id tenant_id = self.tenants.first().id
network = self.networks.first() network = self.networks.first()
extensions = self.api_extensions.list() extensions = self.api_extensions.list()
api.keystone.tenant_list(IsA(http.HttpRequest)).AndReturn([tenants, api.keystone.tenant_list(
False]) IsA(http.HttpRequest)
).MultipleTimes().AndReturn([tenants, False])
api.neutron.list_extensions( api.neutron.list_extensions(
IsA(http.HttpRequest)).AndReturn(extensions) IsA(http.HttpRequest)).AndReturn(extensions)
self.mox.ReplayAll() self.mox.ReplayAll()

View File

@ -18,6 +18,7 @@ from django.conf import settings
from django.core.urlresolvers import reverse from django.core.urlresolvers import reverse
from django import http from django import http
from django.test.utils import override_settings from django.test.utils import override_settings
from django.utils.http import urlunquote
from mox3.mox import IsA # noqa from mox3.mox import IsA # noqa
from openstack_dashboard import api from openstack_dashboard import api
@ -92,7 +93,7 @@ class VolumeTests(test.BaseAdminViewTests):
self.mox.ReplayAll() self.mox.ReplayAll()
res = self.client.get(url) res = self.client.get(urlunquote(url))
self.assertTemplateUsed(res, 'admin/volumes/index.html') self.assertTemplateUsed(res, 'admin/volumes/index.html')
self.assertEqual(res.status_code, 200) self.assertEqual(res.status_code, 200)
@ -190,8 +191,8 @@ class VolumeTests(test.BaseAdminViewTests):
.AndReturn(True) .AndReturn(True)
self.mox.ReplayAll() self.mox.ReplayAll()
res = self.client.get(reverse( url = reverse('horizon:admin:volumes:volume_types_tab')
'horizon:admin:volumes:volume_types_tab')) res = self.client.get(urlunquote(url))
self.assertEqual(res.status_code, 200) self.assertEqual(res.status_code, 200)
self.assertTemplateUsed( self.assertTemplateUsed(
@ -216,10 +217,11 @@ class VolumeTests(test.BaseAdminViewTests):
AndReturn([self.tenants.list(), False]) AndReturn([self.tenants.list(), False])
self.mox.ReplayAll() self.mox.ReplayAll()
res = self.client.get(reverse('horizon:admin:volumes:snapshots_tab')) url = reverse('horizon:admin:volumes:snapshots_tab')
res = self.client.get(urlunquote(url))
self.assertEqual(res.status_code, 200) self.assertEqual(res.status_code, 200)
self.assertTemplateUsed(res, 'horizon/common/_detail_table.html') self.assertTemplateUsed(res, 'admin/volumes/index.html')
snapshots = res.context['volume_snapshots_table'].data snapshots = res.context['volume_snapshots_table'].data
self.assertItemsEqual(snapshots, self.cinder_volume_snapshots.list()) self.assertItemsEqual(snapshots, self.cinder_volume_snapshots.list())
@ -240,7 +242,7 @@ class VolumeTests(test.BaseAdminViewTests):
self.mox.ReplayAll() self.mox.ReplayAll()
res = self.client.get(url) res = self.client.get(urlunquote(url))
self.assertTemplateUsed(res, 'admin/volumes/index.html') self.assertTemplateUsed(res, 'admin/volumes/index.html')
self.assertEqual(res.status_code, 200) self.assertEqual(res.status_code, 200)

View File

@ -16,14 +16,9 @@ from django.utils.translation import ugettext_lazy as _
import horizon import horizon
from openstack_dashboard.dashboards.identity import dashboard
class NGUsers(horizon.Panel): class NGUsers(horizon.Panel):
name = _("Users") name = _("Users")
slug = 'ngusers' slug = 'ngusers'
policy_rules = (("identity", "identity:get_user"), policy_rules = (("identity", "identity:get_user"),
("identity", "identity:list_users")) ("identity", "identity:list_users"))
dashboard.Identity.register(NGUsers)

View File

@ -18,6 +18,7 @@
from socket import timeout as socket_timeout # noqa from socket import timeout as socket_timeout # noqa
import django
from django.core.urlresolvers import reverse from django.core.urlresolvers import reverse
from django import http from django import http
from django.test.utils import override_settings from django.test.utils import override_settings
@ -228,6 +229,19 @@ class UsersViewTests(test.BaseAdminViewTests):
api.keystone.role_list(IgnoreArg()).AndReturn(self.roles.list()) api.keystone.role_list(IgnoreArg()).AndReturn(self.roles.list())
api.keystone.get_default_role(IgnoreArg()) \ api.keystone.get_default_role(IgnoreArg()) \
.AndReturn(self.roles.first()) .AndReturn(self.roles.first())
if django.VERSION >= (1, 9):
if api.keystone.VERSIONS.active >= 3:
api.keystone.tenant_list(
IgnoreArg(), domain=domain_id).AndReturn(
[self.tenants.list(), False])
else:
api.keystone.tenant_list(
IgnoreArg(), user=None).AndReturn(
[self.tenants.list(), False])
api.keystone.role_list(IgnoreArg()).AndReturn(self.roles.list())
api.keystone.get_default_role(IgnoreArg()) \
.AndReturn(self.roles.first())
self.mox.ReplayAll() self.mox.ReplayAll()
@ -268,6 +282,19 @@ class UsersViewTests(test.BaseAdminViewTests):
api.keystone.role_list(IgnoreArg()).AndReturn(self.roles.list()) api.keystone.role_list(IgnoreArg()).AndReturn(self.roles.list())
api.keystone.get_default_role(IgnoreArg()) \ api.keystone.get_default_role(IgnoreArg()) \
.AndReturn(self.roles.first()) .AndReturn(self.roles.first())
if django.VERSION >= (1, 9):
if api.keystone.VERSIONS.active >= 3:
api.keystone.tenant_list(
IgnoreArg(), domain=domain_id).AndReturn(
[self.tenants.list(), False])
else:
api.keystone.tenant_list(
IgnoreArg(), user=None).AndReturn(
[self.tenants.list(), False])
api.keystone.role_list(IgnoreArg()).AndReturn(self.roles.list())
api.keystone.get_default_role(IgnoreArg()) \
.AndReturn(self.roles.first())
self.mox.ReplayAll() self.mox.ReplayAll()
@ -311,6 +338,19 @@ class UsersViewTests(test.BaseAdminViewTests):
api.keystone.role_list(IgnoreArg()).AndReturn(self.roles.list()) api.keystone.role_list(IgnoreArg()).AndReturn(self.roles.list())
api.keystone.get_default_role(IgnoreArg()) \ api.keystone.get_default_role(IgnoreArg()) \
.AndReturn(self.roles.first()) .AndReturn(self.roles.first())
if django.VERSION >= (1, 9):
if api.keystone.VERSIONS.active >= 3:
api.keystone.tenant_list(
IgnoreArg(), domain=domain_id).AndReturn(
[self.tenants.list(), False])
else:
api.keystone.tenant_list(
IgnoreArg(), user=None).AndReturn(
[self.tenants.list(), False])
api.keystone.role_list(IgnoreArg()).AndReturn(self.roles.list())
api.keystone.get_default_role(IgnoreArg()) \
.AndReturn(self.roles.first())
self.mox.ReplayAll() self.mox.ReplayAll()

View File

@ -18,6 +18,7 @@
import cgi import cgi
import django
from django.conf import settings from django.conf import settings
from django.core.urlresolvers import reverse from django.core.urlresolvers import reverse
from django import http from django import http
@ -410,6 +411,12 @@ class SecurityGroupsViewTests(test.TestCase):
IsA(http.HttpRequest)).AndReturn(self.secgroup_backend) IsA(http.HttpRequest)).AndReturn(self.secgroup_backend)
api.network.security_group_list( api.network.security_group_list(
IsA(http.HttpRequest)).AndReturn(sec_group_list) IsA(http.HttpRequest)).AndReturn(sec_group_list)
if django.VERSION >= (1, 9):
api.network.security_group_backend(
IsA(http.HttpRequest)).AndReturn(self.secgroup_backend)
api.network.security_group_list(
IsA(http.HttpRequest)).AndReturn(sec_group_list)
self.mox.ReplayAll() self.mox.ReplayAll()
formData = {'method': 'AddRule', formData = {'method': 'AddRule',
@ -435,6 +442,13 @@ class SecurityGroupsViewTests(test.TestCase):
IsA(http.HttpRequest)).AndReturn(self.secgroup_backend) IsA(http.HttpRequest)).AndReturn(self.secgroup_backend)
api.network.security_group_list( api.network.security_group_list(
IsA(http.HttpRequest)).AndReturn(sec_group_list) IsA(http.HttpRequest)).AndReturn(sec_group_list)
if django.VERSION >= (1, 9):
for i in range(3):
api.network.security_group_backend(
IsA(http.HttpRequest)).AndReturn(self.secgroup_backend)
api.network.security_group_list(
IsA(http.HttpRequest)).AndReturn(sec_group_list)
self.mox.ReplayAll() self.mox.ReplayAll()
formData = {'method': 'AddRule', formData = {'method': 'AddRule',
@ -490,6 +504,13 @@ class SecurityGroupsViewTests(test.TestCase):
api.network.security_group_list( api.network.security_group_list(
IsA(http.HttpRequest)).AndReturn(sec_group_list) IsA(http.HttpRequest)).AndReturn(sec_group_list)
if django.VERSION >= (1, 9):
for i in range(4):
api.network.security_group_backend(
IsA(http.HttpRequest)).AndReturn(self.secgroup_backend)
api.network.security_group_list(
IsA(http.HttpRequest)).AndReturn(sec_group_list)
self.mox.ReplayAll() self.mox.ReplayAll()
formData = {'method': 'AddRule', formData = {'method': 'AddRule',

View File

@ -4511,7 +4511,8 @@ class InstanceTests(helpers.TestCase):
confirm_password=pass2, confirm_password=pass2,
disk_config='MANUAL') disk_config='MANUAL')
self.assertContains(res, "Passwords do not match.") self.assertEqual(res.context['form'].errors['__all__'],
["Passwords do not match."])
@helpers.create_stubs(instance_rebuild_post_stubs) @helpers.create_stubs(instance_rebuild_post_stubs)
def test_rebuild_instance_post_with_empty_string(self): def test_rebuild_instance_post_with_empty_string(self):

View File

@ -13,6 +13,7 @@
import json import json
import logging import logging
import django
from django.conf import settings from django.conf import settings
from django.utils import html from django.utils import html
from django.utils.translation import ugettext_lazy as _ from django.utils.translation import ugettext_lazy as _
@ -125,6 +126,13 @@ class TemplateForm(forms.SelfHandlingForm):
widget=forms.widgets.Textarea(attrs=attributes), widget=forms.widgets.Textarea(attrs=attributes),
required=False) required=False)
if django.VERSION >= (1, 9):
# Note(Itxaka): On django>=1.9 Charfield has an strip option that
# we need to set to False as to not hit
# https://bugs.launchpad.net/python-heatclient/+bug/1546166
environment_data.strip = False
template_data.strip = False
def __init__(self, *args, **kwargs): def __init__(self, *args, **kwargs):
self.next_view = kwargs.pop('next_view') self.next_view = kwargs.pop('next_view')
super(TemplateForm, self).__init__(*args, **kwargs) super(TemplateForm, self).__init__(*args, **kwargs)
@ -252,6 +260,12 @@ class CreateStackForm(forms.SelfHandlingForm):
environment_data = forms.CharField( environment_data = forms.CharField(
widget=forms.widgets.HiddenInput, widget=forms.widgets.HiddenInput,
required=False) required=False)
if django.VERSION >= (1, 9):
# Note(Itxaka): On django>=1.9 Charfield has an strip option that
# we need to set to False as to not hit
# https://bugs.launchpad.net/python-heatclient/+bug/1546166
environment_data.strip = False
parameters = forms.CharField( parameters = forms.CharField(
widget=forms.widgets.HiddenInput) widget=forms.widgets.HiddenInput)
stack_name = forms.RegexField( stack_name = forms.RegexField(

View File

@ -54,5 +54,5 @@
{% endblock %} {% endblock %}
{% block modal-footer %} {% block modal-footer %}
<a href="{% url 'horizon:project:stack:index' %}" class="btn btn-default cancel">{% trans "Close" %}</a> <a href="{% url 'horizon:project:stacks:index' %}" class="btn btn-default cancel">{% trans "Close" %}</a>
{% endblock %} {% endblock %}

View File

@ -70,21 +70,17 @@ class VolumeBackupsViewTests(test.TestCase):
AndReturn(volumes) AndReturn(volumes)
api.cinder.volume_backup_delete(IsA(http.HttpRequest), backup.id) api.cinder.volume_backup_delete(IsA(http.HttpRequest), backup.id)
api.cinder.volume_backup_list_paged(
IsA(http.HttpRequest), marker=None, sort_dir='desc',
paginate=True).AndReturn([vol_backups, False, False])
api.cinder.volume_list(IsA(http.HttpRequest)). \
AndReturn(volumes)
self.mox.ReplayAll() self.mox.ReplayAll()
formData = {'action': formData = {'action':
'volume_backups__delete__%s' % backup.id} 'volume_backups__delete__%s' % backup.id}
res = self.client.post(INDEX_URL + res = self.client.post(INDEX_URL +
"?tab=volumes_and_snapshots__backups_tab", "?tab=volumes_and_snapshots__backups_tab",
formData, follow=True) formData)
self.assertIn("Scheduled deletion of Volume Backup: backup1", self.assertRedirectsNoFollow(res, INDEX_URL +
[m.message for m in res.context['messages']]) "?tab=volumes_and_snapshots__backups_tab")
self.assertMessageCount(success=1)
@test.create_stubs({api.cinder: ('volume_backup_get', 'volume_get')}) @test.create_stubs({api.cinder: ('volume_backup_get', 'volume_get')})
def test_volume_backup_detail_get(self): def test_volume_backup_detail_get(self):

View File

@ -10,8 +10,10 @@
# License for the specific language governing permissions and limitations # License for the specific language governing permissions and limitations
# under the License. # under the License.
import django
from django.core.urlresolvers import reverse from django.core.urlresolvers import reverse
from django import http from django import http
from django.utils.http import urlunquote
from mox3.mox import IsA # noqa from mox3.mox import IsA # noqa
from openstack_dashboard.api import cinder from openstack_dashboard.api import cinder
@ -19,7 +21,8 @@ from openstack_dashboard.test import helpers as test
VOLUME_INDEX_URL = reverse('horizon:project:volumes:index') VOLUME_INDEX_URL = reverse('horizon:project:volumes:index')
VOLUME_CGROUPS_TAB_URL = reverse('horizon:project:volumes:cgroups_tab') VOLUME_CGROUPS_TAB_URL = urlunquote(reverse(
'horizon:project:volumes:cgroups_tab'))
class ConsistencyGroupTests(test.TestCase): class ConsistencyGroupTests(test.TestCase):
@ -111,8 +114,9 @@ class ConsistencyGroupTests(test.TestCase):
AndReturn(cgroups) AndReturn(cgroups)
cinder.volume_cgroup_delete(IsA(http.HttpRequest), cgroup.id, cinder.volume_cgroup_delete(IsA(http.HttpRequest), cgroup.id,
force=False) force=False)
cinder.volume_cgroup_list_with_vol_type_names(IsA(http.HttpRequest)).\ if django.VERSION < (1, 9):
AndReturn(cgroups) cinder.volume_cgroup_list_with_vol_type_names(
IsA(http.HttpRequest)).AndReturn(cgroups)
self.mox.ReplayAll() self.mox.ReplayAll()

View File

@ -108,7 +108,8 @@ class VolumeSnapshotsViewTests(test.TestCase):
@test.create_stubs({api.cinder: ('volume_snapshot_list_paged', @test.create_stubs({api.cinder: ('volume_snapshot_list_paged',
'volume_list', 'volume_list',
'volume_backup_supported', 'volume_backup_supported',
'volume_snapshot_delete')}) 'volume_snapshot_delete',
'tenant_absolute_limits')})
def test_delete_volume_snapshot(self): def test_delete_volume_snapshot(self):
vol_snapshots = self.cinder_volume_snapshots.list() vol_snapshots = self.cinder_volume_snapshots.list()
volumes = self.cinder_volumes.list() volumes = self.cinder_volumes.list()
@ -123,19 +124,14 @@ class VolumeSnapshotsViewTests(test.TestCase):
AndReturn(volumes) AndReturn(volumes)
api.cinder.volume_snapshot_delete(IsA(http.HttpRequest), snapshot.id) api.cinder.volume_snapshot_delete(IsA(http.HttpRequest), snapshot.id)
api.cinder.volume_snapshot_list_paged(
IsA(http.HttpRequest), paginate=True, marker=None,
sort_dir='desc').AndReturn([[], False, False])
api.cinder.volume_list(IsA(http.HttpRequest)). \
AndReturn(volumes)
self.mox.ReplayAll() self.mox.ReplayAll()
formData = {'action': formData = {'action':
'volume_snapshots__delete__%s' % snapshot.id} 'volume_snapshots__delete__%s' % snapshot.id}
res = self.client.post(VOLUME_SNAPSHOTS_TAB_URL, formData, follow=True) res = self.client.post(VOLUME_SNAPSHOTS_TAB_URL, formData)
self.assertIn("Scheduled deletion of Volume Snapshot: test snapshot", self.assertRedirectsNoFollow(res, VOLUME_SNAPSHOTS_TAB_URL)
[m.message for m in res.context['messages']]) self.assertMessageCount(success=1)
@test.create_stubs({api.cinder: ('volume_snapshot_get', 'volume_get')}) @test.create_stubs({api.cinder: ('volume_snapshot_get', 'volume_get')})
def test_volume_snapshot_detail_get(self): def test_volume_snapshot_detail_get(self):

View File

@ -18,6 +18,7 @@ from django.conf import settings
from django.core.urlresolvers import reverse from django.core.urlresolvers import reverse
from django import http from django import http
from django.test.utils import override_settings from django.test.utils import override_settings
from django.utils.http import urlunquote
from mox3.mox import IsA # noqa from mox3.mox import IsA # noqa
@ -32,8 +33,10 @@ from openstack_dashboard.test import helpers as test
INDEX_URL = reverse('horizon:project:volumes:index') INDEX_URL = reverse('horizon:project:volumes:index')
VOLUME_SNAPSHOTS_TAB_URL = reverse('horizon:project:volumes:snapshots_tab') VOLUME_SNAPSHOTS_TAB_URL = urlunquote(reverse(
VOLUME_BACKUPS_TAB_URL = reverse('horizon:project:volumes:backups_tab') 'horizon:project:volumes:snapshots_tab'))
VOLUME_BACKUPS_TAB_URL = urlunquote(reverse(
'horizon:project:volumes:backups_tab'))
class VolumeAndSnapshotsAndBackupsTests(test.TestCase): class VolumeAndSnapshotsAndBackupsTests(test.TestCase):
@ -126,7 +129,7 @@ class VolumeAndSnapshotsAndBackupsTests(test.TestCase):
AndReturn(self.cinder_limits['absolute']) AndReturn(self.cinder_limits['absolute'])
self.mox.ReplayAll() self.mox.ReplayAll()
res = self.client.get(url) res = self.client.get(urlunquote(url))
self.assertEqual(res.status_code, 200) self.assertEqual(res.status_code, 200)
self.assertTemplateUsed(res, 'project/volumes/index.html') self.assertTemplateUsed(res, 'project/volumes/index.html')
@ -223,7 +226,7 @@ class VolumeAndSnapshotsAndBackupsTests(test.TestCase):
self.cinder_volumes.list()) self.cinder_volumes.list())
self.mox.ReplayAll() self.mox.ReplayAll()
res = self.client.get(url) res = self.client.get(urlunquote(url))
self.assertEqual(res.status_code, 200) self.assertEqual(res.status_code, 200)
self.assertTemplateUsed(res, 'project/volumes/index.html') self.assertTemplateUsed(res, 'project/volumes/index.html')
@ -312,7 +315,7 @@ class VolumeAndSnapshotsAndBackupsTests(test.TestCase):
self.cinder_volumes.list()) self.cinder_volumes.list())
self.mox.ReplayAll() self.mox.ReplayAll()
res = self.client.get(url) res = self.client.get(urlunquote(url))
self.assertEqual(res.status_code, 200) self.assertEqual(res.status_code, 200)
self.assertTemplateUsed(res, 'project/volumes/index.html') self.assertTemplateUsed(res, 'project/volumes/index.html')

View File

@ -16,10 +16,12 @@
# License for the specific language governing permissions and limitations # License for the specific language governing permissions and limitations
# under the License. # under the License.
import django
from django.core.urlresolvers import reverse from django.core.urlresolvers import reverse
from django.forms import widgets from django.forms import widgets
from django import http from django import http
from django.test.utils import override_settings from django.test.utils import override_settings
from django.utils.http import urlunquote
from mox3.mox import IsA # noqa from mox3.mox import IsA # noqa
import six import six
@ -32,7 +34,8 @@ from openstack_dashboard.usage import quotas
VOLUME_INDEX_URL = reverse('horizon:project:volumes:index') VOLUME_INDEX_URL = reverse('horizon:project:volumes:index')
VOLUME_VOLUMES_TAB_URL = reverse('horizon:project:volumes:volumes_tab') VOLUME_VOLUMES_TAB_URL = urlunquote(reverse(
'horizon:project:volumes:volumes_tab'))
SEARCH_OPTS = dict(status=api.cinder.VOLUME_STATE_AVAILABLE) SEARCH_OPTS = dict(status=api.cinder.VOLUME_STATE_AVAILABLE)
@ -472,8 +475,9 @@ class VolumeViewTests(test.TestCase):
cinder.volume_type_list(IsA(http.HttpRequest)).\ cinder.volume_type_list(IsA(http.HttpRequest)).\
AndReturn(self.volume_types.list()) AndReturn(self.volume_types.list())
cinder.volume_type_list(IsA(http.HttpRequest)).\ if django.VERSION >= (1, 9):
AndReturn(self.volume_types.list()) cinder.volume_type_list(IsA(http.HttpRequest)).\
AndReturn(self.volume_types.list())
cinder.volume_type_default(IsA(http.HttpRequest)).\ cinder.volume_type_default(IsA(http.HttpRequest)).\
AndReturn(self.volume_types.first()) AndReturn(self.volume_types.first())
quotas.tenant_limit_usages(IsA(http.HttpRequest)).\ quotas.tenant_limit_usages(IsA(http.HttpRequest)).\
@ -482,9 +486,13 @@ class VolumeViewTests(test.TestCase):
str(snapshot.id)).AndReturn(snapshot) str(snapshot.id)).AndReturn(snapshot)
cinder.volume_get(IsA(http.HttpRequest), snapshot.volume_id).\ cinder.volume_get(IsA(http.HttpRequest), snapshot.volume_id).\
AndReturn(self.cinder_volumes.first()) AndReturn(self.cinder_volumes.first())
if django.VERSION >= (1, 9):
quotas.tenant_limit_usages(IsA(http.HttpRequest)).\ cinder.volume_type_default(IsA(http.HttpRequest)). \
AndReturn(usage_limit) AndReturn(self.volume_types.first())
cinder.volume_snapshot_get(IsA(http.HttpRequest),
str(snapshot.id)).AndReturn(snapshot)
cinder.volume_get(IsA(http.HttpRequest), snapshot.volume_id). \
AndReturn(self.cinder_volumes.first())
self.mox.ReplayAll() self.mox.ReplayAll()
@ -649,8 +657,9 @@ class VolumeViewTests(test.TestCase):
cinder.volume_type_list(IsA(http.HttpRequest)).\ cinder.volume_type_list(IsA(http.HttpRequest)).\
AndReturn(self.volume_types.list()) AndReturn(self.volume_types.list())
cinder.volume_type_list(IsA(http.HttpRequest)).\ if django.VERSION >= (1, 9):
AndReturn(self.volume_types.list()) cinder.volume_type_list(IsA(http.HttpRequest)).\
AndReturn(self.volume_types.list())
cinder.volume_type_default(IsA(http.HttpRequest)).\ cinder.volume_type_default(IsA(http.HttpRequest)).\
AndReturn(self.volume_types.first()) AndReturn(self.volume_types.first())
quotas.tenant_limit_usages(IsA(http.HttpRequest)).\ quotas.tenant_limit_usages(IsA(http.HttpRequest)).\
@ -661,8 +670,15 @@ class VolumeViewTests(test.TestCase):
.AndReturn(True) .AndReturn(True)
cinder.availability_zone_list(IsA(http.HttpRequest)).AndReturn( cinder.availability_zone_list(IsA(http.HttpRequest)).AndReturn(
self.cinder_availability_zones.list()) self.cinder_availability_zones.list())
quotas.tenant_limit_usages(IsA(http.HttpRequest)).\ if django.VERSION >= (1, 9):
AndReturn(usage_limit) cinder.volume_type_default(IsA(http.HttpRequest)). \
AndReturn(self.volume_types.first())
api.glance.image_get(IsA(http.HttpRequest),
str(image.id)).AndReturn(image)
cinder.extension_supported(IsA(http.HttpRequest),
'AvailabilityZones').AndReturn(True)
cinder.availability_zone_list(IsA(http.HttpRequest)).AndReturn(
self.cinder_availability_zones.list())
self.mox.ReplayAll() self.mox.ReplayAll()
@ -696,8 +712,9 @@ class VolumeViewTests(test.TestCase):
cinder.volume_type_list(IsA(http.HttpRequest)).\ cinder.volume_type_list(IsA(http.HttpRequest)).\
AndReturn(self.volume_types.list()) AndReturn(self.volume_types.list())
cinder.volume_type_list(IsA(http.HttpRequest)).\ if django.VERSION >= (1, 9):
AndReturn(self.volume_types.list()) cinder.volume_type_list(IsA(http.HttpRequest)).\
AndReturn(self.volume_types.list())
cinder.volume_type_default(IsA(http.HttpRequest)).\ cinder.volume_type_default(IsA(http.HttpRequest)).\
AndReturn(self.volume_types.first()) AndReturn(self.volume_types.first())
quotas.tenant_limit_usages(IsA(http.HttpRequest)).\ quotas.tenant_limit_usages(IsA(http.HttpRequest)).\
@ -708,8 +725,15 @@ class VolumeViewTests(test.TestCase):
.AndReturn(True) .AndReturn(True)
cinder.availability_zone_list(IsA(http.HttpRequest)).AndReturn( cinder.availability_zone_list(IsA(http.HttpRequest)).AndReturn(
self.cinder_availability_zones.list()) self.cinder_availability_zones.list())
quotas.tenant_limit_usages(IsA(http.HttpRequest)).\ if django.VERSION >= (1, 9):
AndReturn(usage_limit) cinder.volume_type_default(IsA(http.HttpRequest)).\
AndReturn(self.volume_types.first())
api.glance.image_get(IsA(http.HttpRequest),
str(image.id)).AndReturn(image)
cinder.extension_supported(IsA(http.HttpRequest),
'AvailabilityZones').AndReturn(True)
cinder.availability_zone_list(IsA(http.HttpRequest)).AndReturn(
self.cinder_availability_zones.list())
self.mox.ReplayAll() self.mox.ReplayAll()
@ -753,8 +777,9 @@ class VolumeViewTests(test.TestCase):
cinder.volume_type_list(IsA(http.HttpRequest)).\ cinder.volume_type_list(IsA(http.HttpRequest)).\
AndReturn(self.volume_types.list()) AndReturn(self.volume_types.list())
cinder.volume_type_list(IsA(http.HttpRequest)).\ if django.VERSION >= (1, 9):
AndReturn(self.volume_types.list()) cinder.volume_type_list(IsA(http.HttpRequest)).\
AndReturn(self.volume_types.list())
cinder.volume_type_default(IsA(http.HttpRequest)).\ cinder.volume_type_default(IsA(http.HttpRequest)).\
AndReturn(self.volume_types.first()) AndReturn(self.volume_types.first())
quotas.tenant_limit_usages(IsA(http.HttpRequest)).\ quotas.tenant_limit_usages(IsA(http.HttpRequest)).\
@ -778,8 +803,29 @@ class VolumeViewTests(test.TestCase):
.AndReturn(True) .AndReturn(True)
cinder.availability_zone_list(IsA(http.HttpRequest)).AndReturn( cinder.availability_zone_list(IsA(http.HttpRequest)).AndReturn(
self.cinder_availability_zones.list()) self.cinder_availability_zones.list())
quotas.tenant_limit_usages(IsA(http.HttpRequest)).\ if django.VERSION >= (1, 9):
AndReturn(usage_limit) cinder.volume_type_default(IsA(http.HttpRequest)).\
AndReturn(self.volume_types.first())
cinder.volume_snapshot_list(IsA(http.HttpRequest),
search_opts=SEARCH_OPTS). \
AndReturn(self.cinder_volume_snapshots.list())
api.glance.image_list_detailed(
IsA(http.HttpRequest),
filters={'is_public': True, 'status': 'active'}) \
.AndReturn([self.images.list(), False, False])
api.glance.image_list_detailed(
IsA(http.HttpRequest),
filters={'property-owner_id': self.tenant.id,
'status': 'active'}) \
.AndReturn([[], False, False])
cinder.volume_list(IsA(
http.HttpRequest),
search_opts=SEARCH_OPTS).AndReturn(self.cinder_volumes.list())
cinder.extension_supported(IsA(http.HttpRequest),
'AvailabilityZones') \
.AndReturn(True)
cinder.availability_zone_list(IsA(http.HttpRequest)).AndReturn(
self.cinder_availability_zones.list())
self.mox.ReplayAll() self.mox.ReplayAll()
@ -810,8 +856,9 @@ class VolumeViewTests(test.TestCase):
cinder.volume_type_list(IsA(http.HttpRequest)).\ cinder.volume_type_list(IsA(http.HttpRequest)).\
AndReturn(self.volume_types.list()) AndReturn(self.volume_types.list())
cinder.volume_type_list(IsA(http.HttpRequest)).\ if django.VERSION >= (1, 9):
AndReturn(self.volume_types.list()) cinder.volume_type_list(IsA(http.HttpRequest)).\
AndReturn(self.volume_types.list())
cinder.volume_type_default(IsA(http.HttpRequest)).\ cinder.volume_type_default(IsA(http.HttpRequest)).\
AndReturn(self.volume_types.first()) AndReturn(self.volume_types.first())
quotas.tenant_limit_usages(IsA(http.HttpRequest)).\ quotas.tenant_limit_usages(IsA(http.HttpRequest)).\
@ -835,8 +882,29 @@ class VolumeViewTests(test.TestCase):
.AndReturn(True) .AndReturn(True)
cinder.availability_zone_list(IsA(http.HttpRequest)).AndReturn( cinder.availability_zone_list(IsA(http.HttpRequest)).AndReturn(
self.cinder_availability_zones.list()) self.cinder_availability_zones.list())
quotas.tenant_limit_usages(IsA(http.HttpRequest)).\ if django.VERSION >= (1, 9):
AndReturn(usage_limit) cinder.volume_type_default(IsA(http.HttpRequest)). \
AndReturn(self.volume_types.first())
cinder.volume_snapshot_list(IsA(http.HttpRequest),
search_opts=SEARCH_OPTS). \
AndReturn(self.cinder_volume_snapshots.list())
api.glance.image_list_detailed(
IsA(http.HttpRequest),
filters={'is_public': True, 'status': 'active'}) \
.AndReturn([self.images.list(), False, False])
api.glance.image_list_detailed(
IsA(http.HttpRequest),
filters={'property-owner_id': self.tenant.id,
'status': 'active'}) \
.AndReturn([[], False, False])
cinder.volume_list(IsA(
http.HttpRequest),
search_opts=SEARCH_OPTS).AndReturn(self.cinder_volumes.list())
cinder.extension_supported(IsA(http.HttpRequest),
'AvailabilityZones') \
.AndReturn(True)
cinder.availability_zone_list(IsA(http.HttpRequest)).AndReturn(
self.cinder_availability_zones.list())
self.mox.ReplayAll() self.mox.ReplayAll()
@ -1434,18 +1502,12 @@ class VolumeViewTests(test.TestCase):
quotas: ('tenant_limit_usages',)}) quotas: ('tenant_limit_usages',)})
def test_extend_volume_with_wrong_size(self): def test_extend_volume_with_wrong_size(self):
volume = self.cinder_volumes.first() volume = self.cinder_volumes.first()
usage_limit = {'maxTotalVolumeGigabytes': 100,
'gigabytesUsed': 20,
'volumesUsed': len(self.cinder_volumes.list()),
'maxTotalVolumes': 6}
formData = {'name': u'A Volume I Am Making', formData = {'name': u'A Volume I Am Making',
'orig_size': volume.size, 'orig_size': volume.size,
'new_size': 10} 'new_size': 10}
cinder.volume_get(IsA(http.HttpRequest), volume.id).\ cinder.volume_get(IsA(http.HttpRequest), volume.id).\
AndReturn(self.cinder_volumes.first()) AndReturn(self.cinder_volumes.first())
quotas.tenant_limit_usages(IsA(http.HttpRequest)).\
AndReturn(usage_limit)
self.mox.ReplayAll() self.mox.ReplayAll()
@ -1574,8 +1636,6 @@ class VolumeViewTests(test.TestCase):
AndReturn(usage_limit) AndReturn(usage_limit)
cinder.volume_get(IsA(http.HttpRequest), volume.id).\ cinder.volume_get(IsA(http.HttpRequest), volume.id).\
AndReturn(self.volumes.first()) AndReturn(self.volumes.first())
quotas.tenant_limit_usages(IsA(http.HttpRequest)).\
AndReturn(usage_limit)
self.mox.ReplayAll() self.mox.ReplayAll()

View File

@ -303,7 +303,7 @@ if os.path.exists(LOCAL_SETTINGS_DIR_PATH):
execfile(os.path.join(dirpath, filename)) execfile(os.path.join(dirpath, filename))
except Exception as e: except Exception as e:
logging.exception( logging.exception(
"Can not exec settings snippet %s" % (filename)) "Can not exec settings snippet %s" % filename)
if not WEBROOT.endswith('/'): if not WEBROOT.endswith('/'):
@ -377,8 +377,14 @@ settings.update_dashboards(
) )
INSTALLED_APPS[0:0] = ADD_INSTALLED_APPS INSTALLED_APPS[0:0] = ADD_INSTALLED_APPS
from openstack_auth import policy
POLICY_CHECK_FUNCTION = policy.check def check(actions, request, target=None):
# Note(Itxaka): This is to prevent circular dependencies and apps not ready
# If you do django imports in your settings, you are gonna have a bad time
from openstack_auth import policy
return policy.check(actions, request, target=None)
POLICY_CHECK_FUNCTION = check
# This base context objects gets added to the offline context generator # This base context objects gets added to the offline context generator
# for each theme configured. # for each theme configured.
@ -393,11 +399,4 @@ COMPRESS_OFFLINE_CONTEXT = 'horizon.themes.offline_context'
if DEBUG: if DEBUG:
logging.basicConfig(level=logging.DEBUG) logging.basicConfig(level=logging.DEBUG)
# during django reloads and an active user is logged in, the monkey
# patch below will not otherwise be applied in time - resulting in developers
# appearing to be logged out. In typical production deployments this section
# below may be omitted, though it should not be harmful
from openstack_auth import utils as auth_utils
auth_utils.patch_middleware_get_user()
CSRF_COOKIE_AGE = None CSRF_COOKIE_AGE = None

View File

@ -29,6 +29,7 @@ from django.core.handlers import wsgi
from django.core import urlresolvers from django.core import urlresolvers
from django.test.client import RequestFactory # noqa from django.test.client import RequestFactory # noqa
from django.test import utils as django_test_utils from django.test import utils as django_test_utils
from django.utils import http
from ceilometerclient.v2 import client as ceilometer_client from ceilometerclient.v2 import client as ceilometer_client
from cinderclient import client as cinder_client from cinderclient import client as cinder_client
@ -232,8 +233,10 @@ class TestCase(horizon_helpers.TestCase):
processing the view which is redirected to. processing the view which is redirected to.
""" """
if django.VERSION >= (1, 9): if django.VERSION >= (1, 9):
self.assertEqual(response._headers.get('location', None), loc = six.text_type(response._headers.get('location', None)[1])
('Location', expected_url)) loc = http.urlunquote(loc)
expected_url = http.urlunquote(expected_url)
self.assertEqual(loc, expected_url)
else: else:
self.assertEqual(response._headers.get('location', None), self.assertEqual(response._headers.get('location', None),
('Location', settings.TESTSERVER + expected_url)) ('Location', settings.TESTSERVER + expected_url))