Merge "Make unit testing less reliant on HTML fragments"

This commit is contained in:
Jenkins 2015-12-03 08:15:21 +00:00 committed by Gerrit Code Review
commit b06b36fcd0
7 changed files with 462 additions and 164 deletions

View File

@ -25,8 +25,6 @@ from mox3.mox import IsA # noqa
import six
from openstack_dashboard import api
from openstack_dashboard.dashboards.project.access_and_security \
.floating_ips import tables
from openstack_dashboard.test import helpers as test
from openstack_dashboard.usage import quotas
@ -214,6 +212,68 @@ class FloatingIpViewTests(test.TestCase):
res = self.client.post(INDEX_URL, {"action": action})
self.assertRedirectsNoFollow(res, INDEX_URL)
@test.create_stubs({api.network: ('floating_ip_supported',
'tenant_floating_ip_list',
'security_group_list',
'floating_ip_pools_list',),
api.nova: ('keypair_list',
'server_list',),
quotas: ('tenant_quota_usages',),
api.base: ('is_service_enabled',)})
def test_allocate_button_attributes(self):
keypairs = self.keypairs.list()
floating_ips = self.floating_ips.list()
floating_pools = self.pools.list()
quota_data = self.quota_usages.first()
quota_data['floating_ips']['available'] = 10
sec_groups = self.security_groups.list()
api.network.floating_ip_supported(
IsA(http.HttpRequest)) \
.AndReturn(True)
api.network.tenant_floating_ip_list(
IsA(http.HttpRequest)) \
.AndReturn(floating_ips)
api.network.security_group_list(
IsA(http.HttpRequest)).MultipleTimes()\
.AndReturn(sec_groups)
api.network.floating_ip_pools_list(
IsA(http.HttpRequest)) \
.AndReturn(floating_pools)
api.nova.keypair_list(
IsA(http.HttpRequest)) \
.AndReturn(keypairs)
api.nova.server_list(
IsA(http.HttpRequest)) \
.AndReturn([self.servers.list(), False])
quotas.tenant_quota_usages(
IsA(http.HttpRequest)).MultipleTimes() \
.AndReturn(quota_data)
api.base.is_service_enabled(
IsA(http.HttpRequest),
'network').MultipleTimes() \
.AndReturn(True)
api.base.is_service_enabled(
IsA(http.HttpRequest),
'ec2').MultipleTimes() \
.AndReturn(False)
self.mox.ReplayAll()
res = self.client.get(INDEX_URL +
"?tab=access_security_tabs__floating_ips_tab")
allocate_action = self.getAndAssertTableAction(res, 'floating_ips',
'allocate')
self.assertEqual(set(['ajax-modal']), set(allocate_action.classes))
self.assertEqual('Allocate IP To Project',
six.text_type(allocate_action.verbose_name))
self.assertEqual(None, allocate_action.policy_rules)
url = 'horizon:project:access_and_security:floating_ips:allocate'
self.assertEqual(url, allocate_action.url)
@test.create_stubs({api.network: ('floating_ip_supported',
'tenant_floating_ip_list',
'security_group_list',
@ -266,19 +326,12 @@ class FloatingIpViewTests(test.TestCase):
res = self.client.get(INDEX_URL +
"?tab=access_security_tabs__floating_ips_tab")
allocate_link = tables.AllocateIP()
url = allocate_link.get_link_url()
classes = (list(allocate_link.get_default_classes())
+ list(allocate_link.classes))
link_name = "%s (%s)" % (six.text_type(allocate_link.verbose_name),
"Quota exceeded")
expected_string = ("<a href='%s' title='%s' class='%s disabled' "
"id='floating_ips__action_allocate'>"
"<span class='fa fa-link'>"
"</span>%s</a>"
% (url, link_name, " ".join(classes), link_name))
self.assertContains(res, expected_string, html=True,
msg_prefix="The create button is not disabled")
allocate_action = self.getAndAssertTableAction(res, 'floating_ips',
'allocate')
self.assertTrue('disabled' in allocate_action.classes,
'The create button should be disabled')
self.assertEqual('Allocate IP To Project (Quota exceeded)',
six.text_type(allocate_action.verbose_name))
class FloatingIpNeutronViewTests(FloatingIpViewTests):

View File

@ -27,8 +27,6 @@ from horizon.workflows import views
from openstack_dashboard import api
from openstack_dashboard.dashboards.project.access_and_security \
import api_access
from openstack_dashboard.dashboards.project.access_and_security \
.security_groups import tables
from openstack_dashboard.test import helpers as test
from openstack_dashboard.usage import quotas
@ -163,6 +161,70 @@ class SecurityGroupTabTests(test.TestCase):
def setUp(self):
super(SecurityGroupTabTests, self).setUp()
@test.create_stubs({api.network: ('floating_ip_supported',
'tenant_floating_ip_list',
'security_group_list',
'floating_ip_pools_list',),
api.nova: ('keypair_list',
'server_list',),
quotas: ('tenant_quota_usages',),
api.base: ('is_service_enabled',)})
def test_create_button_attributes(self):
keypairs = self.keypairs.list()
floating_ips = self.floating_ips.list()
floating_pools = self.pools.list()
sec_groups = self.security_groups.list()
quota_data = self.quota_usages.first()
quota_data['security_groups']['available'] = 10
api.network.floating_ip_supported(
IsA(http.HttpRequest)) \
.AndReturn(True)
api.network.tenant_floating_ip_list(
IsA(http.HttpRequest)) \
.AndReturn(floating_ips)
api.network.floating_ip_pools_list(
IsA(http.HttpRequest)) \
.AndReturn(floating_pools)
api.network.security_group_list(
IsA(http.HttpRequest)) \
.AndReturn(sec_groups)
api.nova.keypair_list(
IsA(http.HttpRequest)) \
.AndReturn(keypairs)
api.nova.server_list(
IsA(http.HttpRequest)) \
.AndReturn([self.servers.list(), False])
quotas.tenant_quota_usages(
IsA(http.HttpRequest)).MultipleTimes() \
.AndReturn(quota_data)
api.base.is_service_enabled(
IsA(http.HttpRequest), 'network').MultipleTimes() \
.AndReturn(True)
api.base.is_service_enabled(
IsA(http.HttpRequest), 'ec2').MultipleTimes() \
.AndReturn(False)
self.mox.ReplayAll()
res = self.client.get(INDEX_URL +
"?tab=access_security_tabs__security_groups_tab")
security_groups = res.context['security_groups_table'].data
self.assertItemsEqual(security_groups, self.security_groups.list())
create_action = self.getAndAssertTableAction(res, 'security_groups',
'create')
self.assertEqual('Create Security Group',
six.text_type(create_action.verbose_name))
self.assertEqual(None, create_action.policy_rules)
self.assertEqual(set(['ajax-modal']), set(create_action.classes))
url = 'horizon:project:access_and_security:security_groups:create'
self.assertEqual(url, create_action.url)
@test.create_stubs({api.network: ('floating_ip_supported',
'tenant_floating_ip_list',
'security_group_list',
@ -217,18 +279,10 @@ class SecurityGroupTabTests(test.TestCase):
security_groups = res.context['security_groups_table'].data
self.assertItemsEqual(security_groups, self.security_groups.list())
create_link = tables.CreateGroup()
url = create_link.get_link_url()
classes = (list(create_link.get_default_classes())
+ list(create_link.classes))
link_name = "%s (%s)" % (six.text_type(create_link.verbose_name),
"Quota exceeded")
expected_string = "<a href='%s' title='%s' class='%s disabled' "\
"id='security_groups__action_create'>" \
"<span class='fa fa-plus'></span>%s</a>" \
% (url, link_name, " ".join(classes), link_name)
self.assertContains(res, expected_string, html=True,
msg_prefix="The create button is not disabled")
create_action = self.getAndAssertTableAction(res, 'security_groups',
'create')
self.assertTrue('disabled' in create_action.classes,
'The create button should be disabled')
def test_create_button_disabled_when_quota_exceeded_neutron_disabled(self):
self._test_create_button_disabled_when_quota_exceeded(False)

View File

@ -28,7 +28,6 @@ from django.core.urlresolvers import reverse
from django.forms import widgets
from django import http
import django.test
from django.utils import encoding
from django.utils.http import urlencode
from mox3.mox import IgnoreArg # noqa
from mox3.mox import IsA # noqa
@ -3587,6 +3586,54 @@ class InstanceTests(helpers.TestCase):
self.test_launch_form_instance_non_int_volume_size(
test_with_profile=True)
@helpers.create_stubs({
api.nova: ('flavor_list', 'server_list', 'tenant_absolute_limits',
'extension_supported',),
api.glance: ('image_list_detailed',),
api.network: ('floating_ip_simple_associate_supported',
'floating_ip_supported',
'servers_update_addresses',),
})
def test_launch_button_attributes(self):
servers = self.servers.list()
limits = self.limits['absolute']
limits['totalInstancesUsed'] = 0
api.nova.extension_supported('AdminActions',
IsA(http.HttpRequest)) \
.MultipleTimes().AndReturn(True)
api.nova.extension_supported('Shelve', IsA(http.HttpRequest)) \
.MultipleTimes().AndReturn(True)
api.nova.flavor_list(IsA(http.HttpRequest)) \
.AndReturn(self.flavors.list())
api.glance.image_list_detailed(IgnoreArg()) \
.AndReturn((self.images.list(), False, False))
search_opts = {'marker': None, 'paginate': True}
api.nova.server_list(IsA(http.HttpRequest), search_opts=search_opts) \
.AndReturn([servers, False])
api.network.servers_update_addresses(IsA(http.HttpRequest), servers)
api.nova.tenant_absolute_limits(IsA(http.HttpRequest), reserved=True) \
.MultipleTimes().AndReturn(limits)
api.network.floating_ip_supported(IsA(http.HttpRequest)) \
.MultipleTimes().AndReturn(True)
api.network.floating_ip_simple_associate_supported(
IsA(http.HttpRequest)).MultipleTimes().AndReturn(True)
self.mox.ReplayAll()
tables.LaunchLink()
res = self.client.get(INDEX_URL)
launch_action = self.getAndAssertTableAction(res, 'instances',
'launch')
self.assertEqual(set(['ajax-modal', 'ajax-update', 'btn-launch']),
set(launch_action.classes))
self.assertEqual('Launch Instance', launch_action.verbose_name)
self.assertEqual('horizon:project:instances:launch', launch_action.url)
self.assertEqual((('compute', 'compute:create'),),
launch_action.policy_rules)
@helpers.create_stubs({
api.nova: ('flavor_list', 'server_list', 'tenant_absolute_limits',
'extension_supported',),
@ -3622,27 +3669,16 @@ class InstanceTests(helpers.TestCase):
self.mox.ReplayAll()
launch = tables.LaunchLink()
url = launch.get_link_url()
classes = list(launch.get_default_classes()) + list(launch.classes)
link_name = "%s (%s)" % (six.text_type(launch.verbose_name),
"Quota exceeded")
tables.LaunchLink()
res = self.client.get(INDEX_URL)
if django.VERSION < (1, 8, 0):
resp_charset = res._charset
else:
resp_charset = res.charset
expected_string = encoding.smart_str(u'''
<a href="%s" title="%s" class="%s disabled"
data-update-url=
"/project/instances/?action=launch&amp;table=instances"
id="instances__action_launch">
<span class="fa fa-cloud-upload"></span>%s</a>
''' % (url, link_name, " ".join(classes), link_name), resp_charset)
self.assertContains(res, expected_string, html=True,
msg_prefix="The launch button is not disabled")
launch_action = self.getAndAssertTableAction(
res, 'instances', 'launch')
self.assertTrue('disabled' in launch_action.classes,
'The launch button should be disabled')
self.assertEqual('Launch Instance (Quota exceeded)',
six.text_type(launch_action.verbose_name))
@helpers.create_stubs({api.glance: ('image_list_detailed',),
api.neutron: ('network_list',),

View File

@ -19,10 +19,9 @@ from django.utils.html import escape
from horizon.workflows import views
from mox3.mox import IsA # noqa
import six
from openstack_dashboard import api
from openstack_dashboard.dashboards.project.networks.subnets import tables\
as subnets_tables
from openstack_dashboard.dashboards.project.networks import tables\
as networks_tables
from openstack_dashboard.dashboards.project.networks import workflows
@ -2013,7 +2012,8 @@ class NetworkSubnetTests(test.TestCase):
class NetworkViewTests(test.TestCase, NetworkStubMixin):
def _test_create_button_shown_when_quota_disabled(
self, expected_string):
self,
find_button_fn):
# if quota_data doesnt contain a networks|subnets|routers key or
# these keys are empty dicts, its disabled
quota_data = self.neutron_quota_usages.first()
@ -2033,11 +2033,14 @@ class NetworkViewTests(test.TestCase, NetworkStubMixin):
networks = res.context['networks_table'].data
self.assertItemsEqual(networks, self.networks.list())
self.assertContains(res, expected_string, True, html=True,
msg_prefix="The enabled create button not shown")
button = find_button_fn(res)
self.assertFalse('disabled' in button.classes,
"The create button should not be disabled")
return button
def _test_create_button_disabled_when_quota_exceeded(
self, expected_string, network_quota=5, subnet_quota=5):
self, find_button_fn, network_quota=5, subnet_quota=5, ):
quota_data = self.neutron_quota_usages.first()
@ -2056,69 +2059,55 @@ class NetworkViewTests(test.TestCase, NetworkStubMixin):
networks = res.context['networks_table'].data
self.assertItemsEqual(networks, self.networks.list())
self.assertContains(res, expected_string, True, html=True,
msg_prefix="The create button is not disabled")
button = find_button_fn(res)
self.assertTrue('disabled' in button.classes,
"The create button should be disabled")
return button
@test.create_stubs({api.neutron: ('network_list',),
quotas: ('tenant_quota_usages',)})
def test_network_create_button_disabled_when_quota_exceeded_index(self):
create_link = networks_tables.CreateNetwork()
url = create_link.get_link_url()
classes = (list(create_link.get_default_classes())
+ list(create_link.classes))
link_name = "%s (%s)" % (create_link.verbose_name, "Quota exceeded")
expected_string = "<a href='%s' title='%s' class='%s disabled' "\
"id='networks__action_create'>" \
"<span class='fa fa-plus'></span>%s</a>" \
% (url, link_name, " ".join(classes), link_name)
self._test_create_button_disabled_when_quota_exceeded(expected_string,
network_quota=0
)
networks_tables.CreateNetwork()
def _find_net_button(res):
return self.getAndAssertTableAction(res, 'networks', 'create')
self._test_create_button_disabled_when_quota_exceeded(_find_net_button,
network_quota=0)
@test.create_stubs({api.neutron: ('network_list',),
quotas: ('tenant_quota_usages',)})
def test_subnet_create_button_disabled_when_quota_exceeded_index(self):
network_id = self.networks.first().id
create_link = networks_tables.CreateSubnet()
url = reverse(create_link.get_link_url(), args=[network_id])
classes = (list(create_link.get_default_classes())
+ list(create_link.classes))
link_name = "%s (%s)" % (create_link.verbose_name, "Quota exceeded")
expected_string = "<a href='%s' class='%s disabled' " \
"id='networks__row_%s__action_subnet'>%s</a>" \
% (url, " ".join(classes), network_id, link_name)
self._test_create_button_disabled_when_quota_exceeded(expected_string,
subnet_quota=0
)
networks_tables.CreateSubnet()
def _find_subnet_button(res):
return self.getAndAssertTableRowAction(res, 'networks',
'subnet', network_id)
self._test_create_button_disabled_when_quota_exceeded(
_find_subnet_button, subnet_quota=0)
@test.create_stubs({api.neutron: ('network_list',),
quotas: ('tenant_quota_usages',)})
def test_network_create_button_shown_when_quota_disabled_index(self):
# if quota_data doesnt contain a networks["available"] key its disabled
create_link = networks_tables.CreateNetwork()
url = create_link.get_link_url()
classes = (list(create_link.get_default_classes())
+ list(create_link.classes))
expected_string = "<a href='%s' title='%s' class='%s' "\
"id='networks__action_create'>" \
"<span class='fa fa-plus'></span>%s</a>" \
% (url, create_link.verbose_name, " ".join(classes),
create_link.verbose_name)
self._test_create_button_shown_when_quota_disabled(expected_string)
networks_tables.CreateNetwork()
self._test_create_button_shown_when_quota_disabled(
lambda res: self.getAndAssertTableAction(res, 'networks', 'create')
)
@test.create_stubs({api.neutron: ('network_list',),
quotas: ('tenant_quota_usages',)})
def test_subnet_create_button_shown_when_quota_disabled_index(self):
# if quota_data doesnt contain a subnets["available"] key, its disabled
network_id = self.networks.first().id
create_link = networks_tables.CreateSubnet()
url = reverse(create_link.get_link_url(), args=[network_id])
classes = (list(create_link.get_default_classes())
+ list(create_link.classes))
expected_string = "<a href='%s' class='%s' "\
"id='networks__row_%s__action_subnet'>%s</a>" \
% (url, " ".join(classes), network_id, create_link.verbose_name)
self._test_create_button_shown_when_quota_disabled(expected_string)
def _find_subnet_button(res):
return self.getAndAssertTableRowAction(res, 'networks',
'subnet', network_id)
self._test_create_button_shown_when_quota_disabled(_find_subnet_button)
@test.create_stubs({api.neutron: ('network_get',
'subnet_list',
@ -2155,17 +2144,65 @@ class NetworkViewTests(test.TestCase, NetworkStubMixin):
subnets = res.context['subnets_table'].data
self.assertItemsEqual(subnets, self.subnets.list())
class FakeTable(object):
kwargs = {'network_id': network_id}
create_link = subnets_tables.CreateSubnet()
create_link.table = FakeTable()
url = create_link.get_link_url()
classes = (list(create_link.get_default_classes())
+ list(create_link.classes))
link_name = "%s (%s)" % (create_link.verbose_name, "Quota exceeded")
expected_string = "<a href='%s' title='%s' class='%s disabled' "\
"id='subnets__action_create'>" \
"<span class='fa fa-plus'></span>%s</a>" \
% (url, link_name, " ".join(classes), link_name)
self.assertContains(res, expected_string, html=True,
msg_prefix="The create button is not disabled")
create_action = self.getAndAssertTableAction(res, 'subnets', 'create')
self.assertTrue('disabled' in create_action.classes,
'The create button should be disabled')
@test.create_stubs({api.neutron: ('network_list',),
quotas: ('tenant_quota_usages',)})
def test_create_button_attributes(self):
create_action = self._test_create_button_shown_when_quota_disabled(
lambda res: self.getAndAssertTableAction(res, 'networks', 'create')
)
self.assertEqual(set(['ajax-modal']), set(create_action.classes))
self.assertEqual('horizon:project:networks:create', create_action.url)
self.assertEqual('Create Network',
six.text_type(create_action.verbose_name))
self.assertEqual((('network', 'create_network'),),
create_action.policy_rules)
@test.create_stubs({api.neutron: ('network_get',
'subnet_list',
'port_list',
'is_extension_supported',),
quotas: ('tenant_quota_usages',)})
def test_create_subnet_button_attributes(self):
network_id = self.networks.first().id
quota_data = self.neutron_quota_usages.first()
quota_data['subnets']['available'] = 1
api.neutron.network_get(
IsA(http.HttpRequest), network_id)\
.MultipleTimes().AndReturn(self.networks.first())
api.neutron.subnet_list(
IsA(http.HttpRequest), network_id=network_id)\
.AndReturn(self.subnets.list())
api.neutron.port_list(
IsA(http.HttpRequest), network_id=network_id)\
.AndReturn([self.ports.first()])
api.neutron.is_extension_supported(
IsA(http.HttpRequest), 'mac-learning')\
.AndReturn(False)
quotas.tenant_quota_usages(
IsA(http.HttpRequest)) \
.MultipleTimes().AndReturn(quota_data)
self.mox.ReplayAll()
res = self.client.get(reverse('horizon:project:networks:detail',
args=[network_id]))
self.assertTemplateUsed(res, 'project/networks/detail.html')
subnets = res.context['subnets_table'].data
self.assertItemsEqual(subnets, self.subnets.list())
create_action = self.getAndAssertTableAction(res, 'subnets', 'create')
self.assertEqual(set(['ajax-modal']), set(create_action.classes))
self.assertEqual('horizon:project:networks:addsubnet',
create_action.url)
self.assertEqual('Create Subnet',
six.text_type(create_action.verbose_name))
self.assertEqual((('network', 'create_subnet'),),
create_action.policy_rules)

View File

@ -23,7 +23,6 @@ import six
from openstack_dashboard import api
from openstack_dashboard.dashboards.project.routers.extensions.routerrules\
import rulemanager
from openstack_dashboard.dashboards.project.routers import tables
from openstack_dashboard.test import helpers as test
from openstack_dashboard.usage import quotas
@ -938,18 +937,11 @@ class RouterViewTests(RouterMixin, test.TestCase):
routers = res.context['Routers_table'].data
self.assertItemsEqual(routers, self.routers.list())
create_link = tables.CreateRouter()
url = create_link.get_link_url()
classes = (list(create_link.get_default_classes())
+ list(create_link.classes))
link_name = "%s (%s)" % (six.text_type(create_link.verbose_name),
"Quota exceeded")
expected_string = "<a href='%s' title='%s' class='%s disabled' "\
"id='Routers__action_create'>" \
"<span class='fa fa-plus'></span>%s</a>" \
% (url, link_name, " ".join(classes), link_name)
self.assertContains(res, expected_string, html=True,
msg_prefix="The create button is not disabled")
create_action = self.getAndAssertTableAction(res, 'Routers', 'create')
self.assertTrue('disabled' in create_action.classes,
'Create button is not disabled')
self.assertEqual('Create Router (Quota exceeded)',
create_action.verbose_name)
@test.create_stubs({api.neutron: ('router_list', 'network_list'),
quotas: ('tenant_quota_usages',)})
@ -973,14 +965,38 @@ class RouterViewTests(RouterMixin, test.TestCase):
routers = res.context['Routers_table'].data
self.assertItemsEqual(routers, self.routers.list())
create_link = tables.CreateRouter()
url = create_link.get_link_url()
classes = (list(create_link.get_default_classes())
+ list(create_link.classes))
link_name = "%s" % (six.text_type(create_link.verbose_name))
expected_string = "<a href='%s' title='%s' class='%s' "\
"id='Routers__action_create'>" \
"<span class='fa fa-plus'></span>%s</a>" \
% (url, link_name, " ".join(classes), link_name)
self.assertContains(res, expected_string, html=True,
msg_prefix="The create button is not displayed")
create_action = self.getAndAssertTableAction(res, 'Routers', 'create')
self.assertFalse('disabled' in create_action.classes,
'Create button should not be disabled')
self.assertEqual('Create Router',
create_action.verbose_name)
@test.create_stubs({api.neutron: ('router_list', 'network_list'),
quotas: ('tenant_quota_usages',)})
def test_create_button_attributes(self):
quota_data = self.neutron_quota_usages.first()
quota_data['routers']['available'] = 10
api.neutron.router_list(
IsA(http.HttpRequest),
tenant_id=self.tenant.id,
search_opts=None).AndReturn(self.routers.list())
quotas.tenant_quota_usages(
IsA(http.HttpRequest)) \
.MultipleTimes().AndReturn(quota_data)
self._mock_external_network_list()
self.mox.ReplayAll()
res = self.client.get(self.INDEX_URL)
self.assertTemplateUsed(res, 'project/routers/index.html')
routers = res.context['Routers_table'].data
self.assertItemsEqual(routers, self.routers.list())
create_action = self.getAndAssertTableAction(res, 'Routers', 'create')
self.assertEqual(set(['ajax-modal']), set(create_action.classes))
self.assertEqual('Create Router',
six.text_type(create_action.verbose_name))
self.assertEqual('horizon:project:routers:create', create_action.url)
self.assertEqual((('network', 'create_router'),),
create_action.policy_rules)

View File

@ -15,7 +15,6 @@
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
# License for the specific language governing permissions and limitations
# under the License.
import django
from django.core.urlresolvers import reverse
from django.forms import widgets
@ -24,11 +23,10 @@ from django.test.utils import override_settings
from mox3.mox import IsA # noqa
import six
from six import moves
from openstack_dashboard import api
from openstack_dashboard.api import cinder
from openstack_dashboard.dashboards.project.volumes \
.volumes import tables
from openstack_dashboard.test import helpers as test
from openstack_dashboard.usage import quotas
@ -1021,6 +1019,50 @@ class VolumeViewTests(test.TestCase):
server.id)
self.assertEqual(res.status_code, 200)
def _get_volume_row_action_from_ajax(self, res, action_name, row_id):
def _matches_row_id(context_row):
return (len(context_row.dicts) > 1 and
isinstance(context_row.dicts[1], dict) and
context_row.dicts[1].get('row_id', None) == row_id)
matching = list(moves.filter(lambda r: _matches_row_id(r),
res.context))
self.assertTrue(len(matching) > 1,
"Expected at least one row matching %s" % row_id)
row = matching[-1].dicts[1]
matching_actions = list(moves.filter(lambda a: a.name == action_name,
row['row_actions']))
self.assertEqual(1, len(matching_actions),
"Expected one row action named '%s'" % action_name)
return matching_actions[0]
@test.create_stubs({cinder: ('tenant_absolute_limits',
'volume_get',)})
def test_create_snapshot_button_attributes(self):
limits = {'maxTotalSnapshots': 2}
limits['totalSnapshotsUsed'] = 1
volume = self.cinder_volumes.first()
cinder.volume_get(IsA(http.HttpRequest), volume.id).AndReturn(volume)
cinder.tenant_absolute_limits(IsA(http.HttpRequest)).AndReturn(limits)
self.mox.ReplayAll()
res_url = (VOLUME_INDEX_URL +
"?action=row_update&table=volumes&obj_id=" + volume.id)
res = self.client.get(res_url, {},
HTTP_X_REQUESTED_WITH='XMLHttpRequest')
snapshot_action = self._get_volume_row_action_from_ajax(
res, 'snapshots', volume.id)
self.assertEqual('horizon:project:volumes:volumes:create_snapshot',
snapshot_action.url)
self.assertEqual(set(['ajax-modal']), set(snapshot_action.classes))
self.assertEqual('Create Snapshot',
six.text_type(snapshot_action.verbose_name))
self.assertEqual((('volume', 'volume:create_snapshot'),),
snapshot_action.policy_rules)
@test.create_stubs({cinder: ('tenant_absolute_limits',
'volume_get',)})
def test_create_snapshot_button_disabled_when_quota_exceeded(self):
@ -1032,25 +1074,57 @@ class VolumeViewTests(test.TestCase):
cinder.tenant_absolute_limits(IsA(http.HttpRequest)).AndReturn(limits)
self.mox.ReplayAll()
create_link = tables.CreateSnapshot()
url = reverse(create_link.get_link_url(), args=[volume.id])
res_url = (VOLUME_INDEX_URL +
"?action=row_update&table=volumes&obj_id=" + volume.id)
res = self.client.get(res_url, {},
HTTP_X_REQUESTED_WITH='XMLHttpRequest')
classes = (list(create_link.get_default_classes())
+ list(create_link.classes))
link_name = "%s (%s)" % (six.text_type(create_link.verbose_name),
"Quota exceeded")
expected_string = "<a href='%s' class=\"%s disabled\" "\
"id=\"volumes__row_%s__action_snapshots\">%s</a>" \
% (url, " ".join(classes), volume.id, link_name)
snapshot_action = self._get_volume_row_action_from_ajax(
res, 'snapshots', volume.id)
self.assertTrue('disabled' in snapshot_action.classes,
'The create snapshot button should be disabled')
self.assertContains(
res, expected_string, html=True,
msg_prefix="The create snapshot button is not disabled")
@test.create_stubs({cinder: ('tenant_absolute_limits',
'volume_list',
'volume_snapshot_list',
'volume_backup_supported',),
api.nova: ('server_list',)})
def test_create_button_attributes(self):
limits = self.cinder_limits['absolute']
limits['maxTotalVolumes'] = 10
limits['totalVolumesUsed'] = 1
volumes = self.cinder_volumes.list()
api.cinder.volume_backup_supported(IsA(http.HttpRequest)). \
MultipleTimes().AndReturn(True)
cinder.volume_list(IsA(http.HttpRequest), search_opts=None)\
.AndReturn(volumes)
cinder.volume_snapshot_list(IsA(http.HttpRequest),
search_opts=None).\
AndReturn([])
api.nova.server_list(IsA(http.HttpRequest), search_opts=None)\
.AndReturn([self.servers.list(), False])
cinder.tenant_absolute_limits(IsA(http.HttpRequest))\
.MultipleTimes().AndReturn(limits)
self.mox.ReplayAll()
res = self.client.get(VOLUME_INDEX_URL)
self.assertTemplateUsed(res, 'project/volumes/index.html')
volumes = res.context['volumes_table'].data
self.assertItemsEqual(volumes, self.cinder_volumes.list())
create_action = self.getAndAssertTableAction(res, 'volumes', 'create')
self.assertEqual(set(['ajax-modal', 'ajax-update', 'btn-create']),
set(create_action.classes))
self.assertEqual('Create Volume',
six.text_type(create_action.verbose_name))
self.assertEqual('horizon:project:volumes:volumes:create',
create_action.url)
self.assertEqual((('volume', 'volume:create'),),
create_action.policy_rules)
@test.create_stubs({cinder: ('tenant_absolute_limits',
'volume_list',
@ -1081,19 +1155,9 @@ class VolumeViewTests(test.TestCase):
volumes = res.context['volumes_table'].data
self.assertItemsEqual(volumes, self.cinder_volumes.list())
create_link = tables.CreateVolume()
url = create_link.get_link_url()
classes = (list(create_link.get_default_classes())
+ list(create_link.classes))
link_name = "%s (%s)" % (six.text_type(create_link.verbose_name),
"Quota exceeded")
expected_string = "<a href='%s' title='%s' class='%s disabled' "\
"id='volumes__action_create' data-update-url=" \
"'/project/volumes/?action=create&amp;table=volumes'> "\
"<span class='fa fa-plus'></span>%s</a>" \
% (url, link_name, " ".join(classes), link_name)
self.assertContains(res, expected_string, html=True,
msg_prefix="The create button is not disabled")
create_action = self.getAndAssertTableAction(res, 'volumes', 'create')
self.assertTrue('disabled' in create_action.classes,
'The create button should be disabled')
@test.create_stubs({cinder: ('tenant_absolute_limits',
'volume_get',),

View File

@ -280,6 +280,44 @@ class TestCase(horizon_helpers.TestCase):
def assertItemsCollectionEqual(self, response, items_list):
self.assertEqual(response.json, {"items": items_list})
def getAndAssertTableRowAction(self, response, table_name,
action_name, row_id):
table = response.context[table_name + '_table']
full_row_id = '%s__row__%s' % (table_name, row_id)
rows = list(moves.filter(lambda x: x.id == full_row_id,
table.get_rows()))
self.assertEqual(1, len(rows),
"Did not find a row matching id '%s'" % row_id)
row_actions = table.get_row_actions(rows[0])
msg_args = (table_name, action_name, row_id)
self.assertTrue(
len(row_actions) > 0,
"No action named '%s' found in table '%s' row '%s'" % msg_args)
self.assertEqual(
1, len(row_actions),
"Multiple actions '%s' found in table '%s' row '%s'" % msg_args)
return row_actions[0]
def getAndAssertTableAction(self, response, table_name, action_name):
table = response.context[table_name + '_table']
table_actions = table.get_table_actions()
actions = list(moves.filter(lambda x: x.name == action_name,
table_actions))
msg_args = (table_name, action_name)
self.assertTrue(
len(actions) > 0,
"No action named '%s' found in table '%s'" % msg_args)
self.assertEqual(
1, len(actions),
"More than one action named '%s' found in table '%s'" % msg_args)
return actions[0]
@staticmethod
def mock_rest_request(**args):
mock_args = {