Add pagination to volume snapshots and backups pages

Do it for both Project (both Snapshots and Backups tabs) and Admin
(only Snapshots tab) dashboards.

To test: set 'Items Per Page' in the UI Settings page to a low number.

Change-Id: I9b16cf31c726055da0afad347e033f3918af3049
Closes-Bug: #1499664
This commit is contained in:
Timur Sufiev 2015-11-30 18:07:39 +03:00
parent abad2d3af4
commit f90b374ad7
11 changed files with 447 additions and 65 deletions

View File

@ -202,6 +202,23 @@ def volume_list(request, search_opts=None, marker=None, sort_dir="desc"):
return volumes
def update_pagination(entities, page_size, marker, sort_dir):
has_more_data, has_prev_data = False, False
if len(entities) > page_size:
has_more_data = True
entities.pop()
if marker is not None:
has_prev_data = True
# first page condition when reached via prev back
elif sort_dir == 'asc' and marker is not None:
has_more_data = True
# last page condition
elif marker is not None:
has_prev_data = True
return entities, has_more_data, has_prev_data
def volume_list_paged(request, search_opts=None, marker=None, paginate=False,
sort_dir="desc"):
"""To see all volumes in the cloud as an admin you can pass in a special
@ -231,17 +248,8 @@ def volume_list_paged(request, search_opts=None, marker=None, paginate=False,
sort=sort):
v.transfer = transfers.get(v.id)
volumes.append(Volume(v))
if len(volumes) > page_size:
has_more_data = True
volumes.pop()
if marker is not None:
has_prev_data = True
# first page condition when reached via prev back
elif sort_dir == 'asc' and marker is not None:
has_more_data = True
# last page condition
elif marker is not None:
has_prev_data = True
volumes, has_more_data, has_prev_data = update_pagination(
volumes, page_size, marker, sort_dir)
else:
for v in c_client.volumes.list(search_opts=search_opts):
v.transfer = transfers.get(v.id)
@ -346,11 +354,40 @@ def volume_snapshot_get(request, snapshot_id):
def volume_snapshot_list(request, search_opts=None):
snapshots, _, __ = volume_snapshot_list_paged(request,
search_opts=search_opts,
paginate=False)
return snapshots
def volume_snapshot_list_paged(request, search_opts=None, marker=None,
paginate=False, sort_dir="desc"):
has_more_data = False
has_prev_data = False
snapshots = []
c_client = cinderclient(request)
if c_client is None:
return []
return [VolumeSnapshot(s) for s in c_client.volume_snapshots.list(
search_opts=search_opts)]
return snapshots, has_more_data, has_more_data
if VERSIONS.active > 1 and paginate:
page_size = utils.get_page_size(request)
# sort_key and sort_dir deprecated in kilo, use sort
# if pagination is true, we use a single sort parameter
# by default, it is "created_at"
sort = 'created_at:' + sort_dir
for s in c_client.volume_snapshots.list(search_opts=search_opts,
limit=page_size + 1,
marker=marker,
sort=sort):
snapshots.append(VolumeSnapshot(s))
snapshots, has_more_data, has_prev_data = update_pagination(
snapshots, page_size, marker, sort_dir)
else:
for s in c_client.volume_snapshots.list(search_opts=search_opts):
snapshots.append(VolumeSnapshot(s))
return snapshots, has_more_data, has_prev_data
def volume_snapshot_create(request, volume_id, name,
@ -399,10 +436,38 @@ def volume_backup_get(request, backup_id):
def volume_backup_list(request):
backups, _, __ = volume_backup_list_paged(request, paginate=False)
return backups
def volume_backup_list_paged(request, marker=None, paginate=False,
sort_dir="desc"):
has_more_data = False
has_prev_data = False
backups = []
c_client = cinderclient(request)
if c_client is None:
return []
return [VolumeBackup(b) for b in c_client.backups.list()]
return backups, has_more_data, has_prev_data
if VERSIONS.active > 1 and paginate:
page_size = utils.get_page_size(request)
# sort_key and sort_dir deprecated in kilo, use sort
# if pagination is true, we use a single sort parameter
# by default, it is "created_at"
sort = 'created_at:' + sort_dir
for b in c_client.backups.list(limit=page_size + 1,
marker=marker,
sort=sort):
backups.append(VolumeBackup(b))
backups, has_more_data, has_prev_data = update_pagination(
backups, page_size, marker, sort_dir)
else:
for b in c_client.backups.list():
backups.append(VolumeBackup(b))
return backups, has_more_data, has_prev_data
def volume_backup_create(request,

View File

@ -67,6 +67,8 @@ class VolumeSnapshotsTable(volumes_tables.VolumesTableBase):
class Meta(object):
name = "volume_snapshots"
verbose_name = _("Volume Snapshots")
pagination_param = 'snapshot_marker'
prev_pagination_param = 'prev_snapshot_marker'
table_actions = (snapshots_tables.VolumeSnapshotsFilterAction,
snapshots_tables.DeleteVolumeSnapshot,)
row_actions = (snapshots_tables.DeleteVolumeSnapshot,

View File

@ -30,7 +30,8 @@ from openstack_dashboard.dashboards.project.volumes \
import tabs as volumes_tabs
class VolumeTab(tabs.TableTab, volumes_tabs.VolumeTableMixIn):
class VolumeTab(volumes_tabs.PagedTableMixin, tabs.TableTab,
volumes_tabs.VolumeTableMixIn):
table_classes = (volumes_tables.VolumesTable,)
name = _("Volumes")
slug = "volumes_tab"
@ -61,12 +62,6 @@ class VolumeTab(tabs.TableTab, volumes_tabs.VolumeTableMixIn):
return volumes
def has_prev_data(self, table):
return self._has_prev_data
def has_more_data(self, table):
return self._has_more_data
class VolumeTypesTab(tabs.TableTab, volumes_tabs.VolumeTableMixIn):
table_classes = (volume_types_tables.VolumeTypesTable,
@ -116,7 +111,7 @@ class VolumeTypesTab(tabs.TableTab, volumes_tabs.VolumeTableMixIn):
return qos_specs
class SnapshotTab(tabs.TableTab):
class SnapshotTab(volumes_tabs.PagedTableMixin, tabs.TableTab):
table_classes = (snapshots_tables.VolumeSnapshotsTable,)
name = _("Volume Snapshots")
slug = "snapshots_tab"
@ -126,9 +121,11 @@ class SnapshotTab(tabs.TableTab):
def get_volume_snapshots_data(self):
if api.base.is_service_enabled(self.request, 'volume'):
try:
snapshots = cinder.volume_snapshot_list(
self.request,
search_opts={'all_tenants': True})
marker, sort_dir = self._get_marker()
snapshots, self._has_more_data, self._has_prev_data = \
cinder.volume_snapshot_list_paged(
self.request, paginate=True, marker=marker,
sort_dir=sort_dir, search_opts={'all_tenants': True})
volumes = cinder.volume_list(
self.request,
search_opts={'all_tenants': True})

View File

@ -21,6 +21,8 @@ from mox3.mox import IsA # noqa
from openstack_dashboard import api
from openstack_dashboard.api import cinder
from openstack_dashboard.api import keystone
from openstack_dashboard.dashboards.project.volumes.snapshots \
import tables as snapshot_tables
from openstack_dashboard.dashboards.project.volumes.volumes \
import tables as volume_tables
from openstack_dashboard.test import helpers as test
@ -174,12 +176,13 @@ class VolumeTests(test.BaseAdminViewTests):
self.assertItemsEqual(qos_specs, self.cinder_qos_specs.list())
@test.create_stubs({cinder: ('volume_list',
'volume_snapshot_list',),
'volume_snapshot_list_paged',),
keystone: ('tenant_list',)})
def test_snapshots_tab(self):
cinder.volume_snapshot_list(IsA(http.HttpRequest), search_opts={
'all_tenants': True}). \
AndReturn(self.cinder_volume_snapshots.list())
cinder.volume_snapshot_list_paged(
IsA(http.HttpRequest), paginate=True, marker=None, sort_dir='desc',
search_opts={'all_tenants': True},).AndReturn(
[self.cinder_volume_snapshots.list(), False, False])
cinder.volume_list(IsA(http.HttpRequest), search_opts={
'all_tenants': True}).\
AndReturn(self.cinder_volumes.list())
@ -193,3 +196,90 @@ class VolumeTests(test.BaseAdminViewTests):
self.assertTemplateUsed(res, 'horizon/common/_detail_table.html')
snapshots = res.context['volume_snapshots_table'].data
self.assertItemsEqual(snapshots, self.cinder_volume_snapshots.list())
@test.create_stubs({cinder: ('volume_list',
'volume_snapshot_list_paged',),
keystone: ('tenant_list',)})
def _test_snapshots_index_paginated(self, marker, sort_dir, snapshots, url,
has_more, has_prev):
cinder.volume_snapshot_list_paged(
IsA(http.HttpRequest), paginate=True, marker=marker,
sort_dir=sort_dir, search_opts={'all_tenants': True}) \
.AndReturn([snapshots, has_more, has_prev])
cinder.volume_list(IsA(http.HttpRequest), search_opts={
'all_tenants': True}).\
AndReturn(self.cinder_volumes.list())
keystone.tenant_list(IsA(http.HttpRequest)) \
.AndReturn([self.tenants.list(), False])
self.mox.ReplayAll()
res = self.client.get(url)
self.assertTemplateUsed(res, 'admin/volumes/index.html')
self.assertEqual(res.status_code, 200)
self.mox.UnsetStubs()
return res
@override_settings(API_RESULT_PAGE_SIZE=1)
def test_snapshots_index_paginated(self):
size = settings.API_RESULT_PAGE_SIZE
mox_snapshots = self.cinder_volume_snapshots.list()
base_url = reverse('horizon:admin:volumes:snapshots_tab')
next = snapshot_tables.VolumeSnapshotsTable._meta.pagination_param
# get first page
expected_snapshots = mox_snapshots[:size]
res = self._test_snapshots_index_paginated(
marker=None, sort_dir="desc", snapshots=expected_snapshots,
url=base_url, has_more=True, has_prev=False)
snapshots = res.context['volume_snapshots_table'].data
self.assertItemsEqual(snapshots, expected_snapshots)
# get second page
expected_snapshots = mox_snapshots[size:2 * size]
marker = expected_snapshots[0].id
url = "&".join([base_url, "=".join([next, marker])])
res = self._test_snapshots_index_paginated(
marker=marker, sort_dir="desc", snapshots=expected_snapshots,
url=url, has_more=True, has_prev=True)
snapshots = res.context['volume_snapshots_table'].data
self.assertItemsEqual(snapshots, expected_snapshots)
# get last page
expected_snapshots = mox_snapshots[-size:]
marker = expected_snapshots[0].id
url = "&".join([base_url, "=".join([next, marker])])
res = self._test_snapshots_index_paginated(
marker=marker, sort_dir="desc", snapshots=expected_snapshots,
url=url, has_more=False, has_prev=True)
snapshots = res.context['volume_snapshots_table'].data
self.assertItemsEqual(snapshots, expected_snapshots)
@override_settings(API_RESULT_PAGE_SIZE=1)
def test_snapshots_index_paginated_prev(self):
size = settings.API_RESULT_PAGE_SIZE
max_snapshots = self.cinder_volume_snapshots.list()
base_url = reverse('horizon:admin:volumes:snapshots_tab')
prev = snapshot_tables.VolumeSnapshotsTable._meta.prev_pagination_param
# prev from some page
expected_snapshots = max_snapshots[size:2 * size]
marker = max_snapshots[0].id
url = "&".join([base_url, "=".join([prev, marker])])
res = self._test_snapshots_index_paginated(
marker=marker, sort_dir="asc", snapshots=expected_snapshots,
url=url, has_more=False, has_prev=True)
snapshots = res.context['volume_snapshots_table'].data
self.assertItemsEqual(snapshots, expected_snapshots)
# back to first page
expected_snapshots = max_snapshots[:size]
marker = max_snapshots[0].id
url = "&".join([base_url, "=".join([prev, marker])])
res = self._test_snapshots_index_paginated(
marker=marker, sort_dir="asc", snapshots=expected_snapshots,
url=url, has_more=True, has_prev=False)
snapshots = res.context['volume_snapshots_table'].data
self.assertItemsEqual(snapshots, expected_snapshots)

View File

@ -139,6 +139,8 @@ class BackupsTable(tables.DataTable):
class Meta(object):
name = "volume_backups"
verbose_name = _("Volume Backups")
pagination_param = 'backup_marker'
prev_pagination_param = 'prev_backup_marker'
status_columns = ("status",)
row_class = UpdateRow
table_actions = (DeleteBackup,)

View File

@ -54,7 +54,7 @@ class VolumeBackupsViewTests(test.TestCase):
@test.create_stubs({api.cinder: ('volume_list',
'volume_backup_supported',
'volume_backup_list',
'volume_backup_list_paged',
'volume_backup_delete')})
def test_delete_volume_backup(self):
vol_backups = self.cinder_volume_backups.list()
@ -63,14 +63,16 @@ class VolumeBackupsViewTests(test.TestCase):
api.cinder.volume_backup_supported(IsA(http.HttpRequest)). \
MultipleTimes().AndReturn(True)
api.cinder.volume_backup_list(IsA(http.HttpRequest)). \
AndReturn(vol_backups)
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)
api.cinder.volume_backup_delete(IsA(http.HttpRequest), backup.id)
api.cinder.volume_backup_list(IsA(http.HttpRequest)). \
AndReturn(vol_backups)
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()

View File

@ -154,6 +154,8 @@ class VolumeSnapshotsTable(volume_tables.VolumesTableBase):
class Meta(object):
name = "volume_snapshots"
verbose_name = _("Volume Snapshots")
pagination_param = 'snapshot_marker'
prev_pagination_param = 'prev_snapshot_marker'
table_actions = (VolumeSnapshotsFilterAction, DeleteVolumeSnapshot,)
row_actions = (CreateVolumeFromSnapshot, LaunchSnapshot,
EditVolumeSnapshot, DeleteVolumeSnapshot)

View File

@ -105,7 +105,7 @@ class VolumeSnapshotsViewTests(test.TestCase):
res = self.client.post(url, formData)
self.assertRedirectsNoFollow(res, VOLUME_SNAPSHOTS_TAB_URL)
@test.create_stubs({api.cinder: ('volume_snapshot_list',
@test.create_stubs({api.cinder: ('volume_snapshot_list_paged',
'volume_list',
'volume_backup_supported',
'volume_snapshot_delete')})
@ -116,14 +116,16 @@ class VolumeSnapshotsViewTests(test.TestCase):
api.cinder.volume_backup_supported(IsA(http.HttpRequest)). \
MultipleTimes().AndReturn(True)
api.cinder.volume_snapshot_list(IsA(http.HttpRequest)). \
AndReturn(vol_snapshots)
api.cinder.volume_snapshot_list_paged(
IsA(http.HttpRequest), paginate=True, marker=None,
sort_dir='desc').AndReturn([vol_snapshots, False, False])
api.cinder.volume_list(IsA(http.HttpRequest)). \
AndReturn(volumes)
api.cinder.volume_snapshot_delete(IsA(http.HttpRequest), snapshot.id)
api.cinder.volume_snapshot_list(IsA(http.HttpRequest)). \
AndReturn([])
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()

View File

@ -89,20 +89,32 @@ class VolumeTableMixIn(object):
server_id = att.get('server_id', None)
att['instance'] = instances.get(server_id, None)
class PagedTableMixin(object):
def __init__(self, *args, **kwargs):
super(PagedTableMixin, self).__init__(*args, **kwargs)
self._has_prev_data = False
self._has_more_data = False
def has_prev_data(self, table):
return self._has_prev_data
def has_more_data(self, table):
return self._has_more_data
def _get_marker(self):
prev_marker = self.request.GET.get(
volume_tables.VolumesTable._meta.prev_pagination_param, None)
meta = self.table_classes[0]._meta
prev_marker = self.request.GET.get(meta.prev_pagination_param, None)
if prev_marker:
return prev_marker, "asc"
else:
marker = self.request.GET.get(
volume_tables.VolumesTable._meta.pagination_param, None)
marker = self.request.GET.get(meta.pagination_param, None)
if marker:
return marker, "desc"
return None, "desc"
class VolumeTab(tabs.TableTab, VolumeTableMixIn):
class VolumeTab(PagedTableMixin, tabs.TableTab, VolumeTableMixIn):
table_classes = (volume_tables.VolumesTable,)
name = _("Volumes")
slug = "volumes_tab"
@ -117,14 +129,8 @@ class VolumeTab(tabs.TableTab, VolumeTableMixIn):
volumes, instances, volume_ids_with_snapshots)
return volumes
def has_prev_data(self, table):
return self._has_prev_data
def has_more_data(self, table):
return self._has_more_data
class SnapshotTab(tabs.TableTab):
class SnapshotTab(PagedTableMixin, tabs.TableTab):
table_classes = (vol_snapshot_tables.VolumeSnapshotsTable,)
name = _("Volume Snapshots")
slug = "snapshots_tab"
@ -133,7 +139,11 @@ class SnapshotTab(tabs.TableTab):
def get_volume_snapshots_data(self):
try:
snapshots = api.cinder.volume_snapshot_list(self.request)
marker, sort_dir = self._get_marker()
snapshots, self._has_more_data, self._has_prev_data = \
api.cinder.volume_snapshot_list_paged(
self.request, paginate=True, marker=marker,
sort_dir=sort_dir)
volumes = api.cinder.volume_list(self.request)
volumes = dict((v.id, v) for v in volumes)
except Exception:
@ -149,7 +159,7 @@ class SnapshotTab(tabs.TableTab):
return snapshots
class BackupsTab(tabs.TableTab, VolumeTableMixIn):
class BackupsTab(PagedTableMixin, tabs.TableTab, VolumeTableMixIn):
table_classes = (backups_tables.BackupsTable,)
name = _("Volume Backups")
slug = "backups_tab"
@ -161,7 +171,11 @@ class BackupsTab(tabs.TableTab, VolumeTableMixIn):
def get_volume_backups_data(self):
try:
backups = api.cinder.volume_backup_list(self.request)
marker, sort_dir = self._get_marker()
backups, self._has_more_data, self._has_prev_data = \
api.cinder.volume_backup_list_paged(
self.request, marker=marker, sort_dir=sort_dir,
paginate=True)
volumes = api.cinder.volume_list(self.request)
volumes = dict((v.id, v) for v in volumes)
for backup in backups:

View File

@ -20,6 +20,10 @@ from django.test.utils import override_settings
from mox3.mox import IsA # noqa
from openstack_dashboard import api
from openstack_dashboard.dashboards.project.volumes.backups \
import tables as backup_tables
from openstack_dashboard.dashboards.project.volumes.snapshots \
import tables as snapshot_tables
from openstack_dashboard.dashboards.project.volumes.volumes \
import tables as volume_tables
from openstack_dashboard.test import helpers as test
@ -30,13 +34,14 @@ VOLUME_SNAPSHOTS_TAB_URL = reverse('horizon:project:volumes:snapshots_tab')
VOLUME_BACKUPS_TAB_URL = reverse('horizon:project:volumes:backups_tab')
class VolumeAndSnapshotsTests(test.TestCase):
class VolumeAndSnapshotsAndBackupsTests(test.TestCase):
@test.create_stubs({api.cinder: ('tenant_absolute_limits',
'volume_list',
'volume_list_paged',
'volume_snapshot_list',
'volume_snapshot_list_paged',
'volume_backup_supported',
'volume_backup_list',
'volume_backup_list_paged',
),
api.nova: ('server_list',)})
def _test_index(self, backup_supported=True):
@ -46,20 +51,23 @@ class VolumeAndSnapshotsTests(test.TestCase):
api.cinder.volume_backup_supported(IsA(http.HttpRequest)).\
MultipleTimes().AndReturn(backup_supported)
api.cinder.volume_list_paged(IsA(http.HttpRequest), marker=None,
sort_dir='desc', search_opts=None,
paginate=True).\
api.cinder.volume_list_paged(
IsA(http.HttpRequest), marker=None, search_opts=None,
sort_dir='desc', paginate=True).\
AndReturn([volumes, False, False])
api.nova.server_list(IsA(http.HttpRequest), search_opts=None).\
AndReturn([self.servers.list(), False])
api.cinder.volume_snapshot_list(
IsA(http.HttpRequest), search_opts=None).AndReturn(vol_snaps)
api.cinder.volume_snapshot_list(IsA(http.HttpRequest)).\
AndReturn(vol_snaps)
api.cinder.volume_snapshot_list_paged(
IsA(http.HttpRequest), paginate=True, marker=None,
sort_dir='desc').AndReturn([vol_snaps, False, False])
api.cinder.volume_list(IsA(http.HttpRequest)).AndReturn(volumes)
if backup_supported:
api.cinder.volume_backup_list(IsA(http.HttpRequest)).\
AndReturn(vol_backups)
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)
api.cinder.tenant_absolute_limits(IsA(http.HttpRequest)).\
MultipleTimes().AndReturn(self.cinder_limits['absolute'])
@ -175,3 +183,181 @@ class VolumeAndSnapshotsTests(test.TestCase):
has_more=True, has_prev=False)
volumes = res.context['volumes_table'].data
self.assertItemsEqual(volumes, expected_volumes)
@test.create_stubs({api.cinder: ('tenant_absolute_limits',
'volume_snapshot_list_paged',
'volume_list',
'volume_backup_supported',
),
api.nova: ('server_list',)})
def _test_snapshots_index_paginated(self, marker, sort_dir, snapshots, url,
has_more, has_prev):
backup_supported = True
api.cinder.volume_backup_supported(IsA(http.HttpRequest)).\
MultipleTimes().AndReturn(backup_supported)
api.cinder.volume_snapshot_list_paged(
IsA(http.HttpRequest), marker=marker, sort_dir=sort_dir,
paginate=True).AndReturn([snapshots, has_more, has_prev])
api.cinder.volume_list(IsA(http.HttpRequest)).AndReturn(
self.cinder_volumes.list())
self.mox.ReplayAll()
res = self.client.get(url)
self.assertEqual(res.status_code, 200)
self.assertTemplateUsed(res, 'project/volumes/index.html')
self.mox.UnsetStubs()
return res
@override_settings(API_RESULT_PAGE_SIZE=1)
def test_snapshots_index_paginated(self):
mox_snapshots = self.cinder_volume_snapshots.list()
size = settings.API_RESULT_PAGE_SIZE
base_url = reverse('horizon:project:volumes:snapshots_tab')
next = snapshot_tables.VolumeSnapshotsTable._meta.pagination_param
# get first page
expected_snapshots = mox_snapshots[:size]
res = self._test_snapshots_index_paginated(
marker=None, sort_dir="desc", snapshots=expected_snapshots,
url=base_url, has_more=True, has_prev=False)
snapshots = res.context['volume_snapshots_table'].data
self.assertItemsEqual(snapshots, expected_snapshots)
# get second page
expected_snapshots = mox_snapshots[size:2 * size]
marker = expected_snapshots[0].id
url = "&".join([base_url, "=".join([next, marker])])
res = self._test_snapshots_index_paginated(
marker=marker, sort_dir="desc", snapshots=expected_snapshots,
url=url, has_more=True, has_prev=True)
snapshots = res.context['volume_snapshots_table'].data
self.assertItemsEqual(snapshots, expected_snapshots)
# get last page
expected_snapshots = mox_snapshots[-size:]
marker = expected_snapshots[0].id
url = "&".join([base_url, "=".join([next, marker])])
res = self._test_snapshots_index_paginated(
marker=marker, sort_dir="desc", snapshots=expected_snapshots,
url=url, has_more=False, has_prev=True)
snapshots = res.context['volume_snapshots_table'].data
self.assertItemsEqual(snapshots, expected_snapshots)
@override_settings(API_RESULT_PAGE_SIZE=1)
def test_snapshots_index_paginated_prev_page(self):
mox_snapshots = self.cinder_volume_snapshots.list()
size = settings.API_RESULT_PAGE_SIZE
base_url = reverse('horizon:project:volumes:snapshots_tab')
prev = snapshot_tables.VolumeSnapshotsTable._meta.prev_pagination_param
# prev from some page
expected_snapshots = mox_snapshots[size:2 * size]
marker = expected_snapshots[0].id
url = "&".join([base_url, "=".join([prev, marker])])
res = self._test_snapshots_index_paginated(
marker=marker, sort_dir="asc", snapshots=expected_snapshots,
url=url, has_more=True, has_prev=True)
snapshots = res.context['volume_snapshots_table'].data
self.assertItemsEqual(snapshots, expected_snapshots)
# back to first page
expected_snapshots = mox_snapshots[:size]
marker = expected_snapshots[0].id
url = "&".join([base_url, "=".join([prev, marker])])
res = self._test_snapshots_index_paginated(
marker=marker, sort_dir="asc", snapshots=expected_snapshots,
url=url, has_more=True, has_prev=False)
snapshots = res.context['volume_snapshots_table'].data
self.assertItemsEqual(snapshots, expected_snapshots)
@test.create_stubs({api.cinder: ('tenant_absolute_limits',
'volume_backup_list_paged',
'volume_list',
'volume_backup_supported',
),
api.nova: ('server_list',)})
def _test_backups_index_paginated(self, marker, sort_dir, backups, url,
has_more, has_prev):
backup_supported = True
api.cinder.volume_backup_supported(IsA(http.HttpRequest)).\
MultipleTimes().AndReturn(backup_supported)
api.cinder.volume_backup_list_paged(
IsA(http.HttpRequest), marker=marker, sort_dir=sort_dir,
paginate=True).AndReturn([backups, has_more, has_prev])
api.cinder.volume_list(IsA(http.HttpRequest)).AndReturn(
self.cinder_volumes.list())
self.mox.ReplayAll()
res = self.client.get(url)
self.assertEqual(res.status_code, 200)
self.assertTemplateUsed(res, 'project/volumes/index.html')
self.mox.UnsetStubs()
return res
@override_settings(API_RESULT_PAGE_SIZE=1)
def test_backups_index_paginated(self):
mox_backups = self.cinder_volume_backups.list()
size = settings.API_RESULT_PAGE_SIZE
base_url = reverse('horizon:project:volumes:backups_tab')
next = backup_tables.BackupsTable._meta.pagination_param
# get first page
expected_backups = mox_backups[:size]
res = self._test_backups_index_paginated(
marker=None, sort_dir="desc", backups=expected_backups,
url=base_url, has_more=True, has_prev=False)
backups = res.context['volume_backups_table'].data
self.assertItemsEqual(backups, expected_backups)
# get second page
expected_backups = mox_backups[size:2 * size]
marker = expected_backups[0].id
url = "&".join([base_url, "=".join([next, marker])])
res = self._test_backups_index_paginated(
marker=marker, sort_dir="desc", backups=expected_backups, url=url,
has_more=True, has_prev=True)
backups = res.context['volume_backups_table'].data
self.assertItemsEqual(backups, expected_backups)
# get last page
expected_backups = mox_backups[-size:]
marker = expected_backups[0].id
url = "&".join([base_url, "=".join([next, marker])])
res = self._test_backups_index_paginated(
marker=marker, sort_dir="desc", backups=expected_backups, url=url,
has_more=False, has_prev=True)
backups = res.context['volume_backups_table'].data
self.assertItemsEqual(backups, expected_backups)
@override_settings(API_RESULT_PAGE_SIZE=1)
def test_backups_index_paginated_prev_page(self):
mox_backups = self.cinder_volume_backups.list()
size = settings.API_RESULT_PAGE_SIZE
base_url = reverse('horizon:project:volumes:backups_tab')
prev = backup_tables.BackupsTable._meta.prev_pagination_param
# prev from some page
expected_backups = mox_backups[size:2 * size]
marker = expected_backups[0].id
url = "&".join([base_url, "=".join([prev, marker])])
res = self._test_backups_index_paginated(
marker=marker, sort_dir="asc", backups=expected_backups, url=url,
has_more=True, has_prev=True)
backups = res.context['volume_backups_table'].data
self.assertItemsEqual(backups, expected_backups)
# back to first page
expected_backups = mox_backups[:size]
marker = expected_backups[0].id
url = "&".join([base_url, "=".join([prev, marker])])
res = self._test_backups_index_paginated(
marker=marker, sort_dir="asc", backups=expected_backups, url=url,
has_more=True, has_prev=False)
backups = res.context['volume_backups_table'].data
self.assertItemsEqual(backups, expected_backups)

View File

@ -185,12 +185,21 @@ def data(TEST):
'size': 80,
'status': 'available',
'volume_id': '31023e92-8008-4c8b-8059-7f2293ff1234'})
snapshot3 = vol_snaps.Snapshot(
vol_snaps.SnapshotManager(None),
{'id': 'c9d0881a-4c0b-4158-a212-ad27e11c2b0e',
'name': '',
'description': 'v2 volume snapshot description 2',
'size': 80,
'status': 'available',
'volume_id': '31023e92-8008-4c8b-8059-7f2293ff1234'})
snapshot.bootable = 'true'
snapshot2.bootable = 'true'
TEST.cinder_volume_snapshots.add(api.cinder.VolumeSnapshot(snapshot))
TEST.cinder_volume_snapshots.add(api.cinder.VolumeSnapshot(snapshot2))
TEST.cinder_volume_snapshots.add(api.cinder.VolumeSnapshot(snapshot3))
TEST.cinder_volume_snapshots.first()._volume = volume
# Volume Type Encryption
@ -233,8 +242,19 @@ def data(TEST):
'container_name': 'volumebackups',
'volume_id': '31023e92-8008-4c8b-8059-7f2293ff1234'})
volume_backup3 = vol_backups.VolumeBackup(
vol_backups.VolumeBackupManager(None),
{'id': 'c321cbb8-3f99-4c3f-a2ef-3edbec842e53',
'name': 'backup3',
'description': 'volume backup 3',
'size': 20,
'status': 'available',
'container_name': 'volumebackups',
'volume_id': '31023e92-8008-4c8b-8059-7f2293ff1234'})
TEST.cinder_volume_backups.add(volume_backup1)
TEST.cinder_volume_backups.add(volume_backup2)
TEST.cinder_volume_backups.add(volume_backup3)
# Volume Encryption
vol_enc_metadata1 = volumes.Volume(