From fdba403d09b6a21997d3f98f987638fde8cb4c39 Mon Sep 17 00:00:00 2001 From: Diana Clarke Date: Thu, 15 Dec 2016 13:20:32 -0500 Subject: [PATCH] Add offset & limit docs & tests A number of endpoints enable pagination via 'limit' & 'offset' query parameters, but don't document or test this functionality. - os-cells - os-security-groups - os-server-groups - os-snapshots - os-virtual-interfaces - os-volume-attachments - os-volumes Change-Id: I5b0ad25f7282f4a13bbb6f21b76e986e1008936a --- api-ref/source/os-cells.inc | 10 ++++++ api-ref/source/os-security-groups.inc | 8 +++++ api-ref/source/os-virtual-interfaces.inc | 2 ++ api-ref/source/os-volume-attachments.inc | 2 ++ api-ref/source/os-volumes.inc | 32 +++++++++++++++++++ .../unit/api/openstack/compute/test_cells.py | 20 ++++++++++++ .../compute/test_neutron_security_groups.py | 7 ++++ .../openstack/compute/test_security_groups.py | 18 +++++++++-- .../openstack/compute/test_server_groups.py | 29 +++++++++++++---- .../api/openstack/compute/test_snapshots.py | 19 +++++++++++ .../compute/test_virtual_interfaces.py | 8 +++++ 11 files changed, 146 insertions(+), 9 deletions(-) diff --git a/api-ref/source/os-cells.inc b/api-ref/source/os-cells.inc index b9ddcbb7229d..e5b403c2dbc0 100644 --- a/api-ref/source/os-cells.inc +++ b/api-ref/source/os-cells.inc @@ -29,6 +29,8 @@ Request .. rest_parameters:: parameters.yaml - tenant_id: tenant_id + - limit: limit_simple + - offset: offset_simple .. TODO(cdent): How do we indicate optionality of a URI parameter? @@ -80,6 +82,14 @@ Normal response codes: 200 Error response codes: badRequest(400), unauthorized(401), forbidden(403), NotImplemented(501) +Request +------- + +.. rest_parameters:: parameters.yaml + + - limit: limit_simple + - offset: offset_simple + Response -------- diff --git a/api-ref/source/os-security-groups.inc b/api-ref/source/os-security-groups.inc index 0d49d92c98cb..37d9e606c48c 100644 --- a/api-ref/source/os-security-groups.inc +++ b/api-ref/source/os-security-groups.inc @@ -28,6 +28,14 @@ Normal response codes: 200 Error response codes: unauthorized(401), forbidden(403), itemNotFound(404) +Request +------- + +.. rest_parameters:: parameters.yaml + + - limit: limit_simple + - offset: offset_simple + Response -------- diff --git a/api-ref/source/os-virtual-interfaces.inc b/api-ref/source/os-virtual-interfaces.inc index 44c95b6f1dcf..98d26ecedf94 100644 --- a/api-ref/source/os-virtual-interfaces.inc +++ b/api-ref/source/os-virtual-interfaces.inc @@ -35,6 +35,8 @@ Request - server_id: server_id_path + - limit: limit_simple + - offset: offset_simple Response -------- diff --git a/api-ref/source/os-volume-attachments.inc b/api-ref/source/os-volume-attachments.inc index 157ed5b974b2..62bdde04dfaf 100644 --- a/api-ref/source/os-volume-attachments.inc +++ b/api-ref/source/os-volume-attachments.inc @@ -25,6 +25,8 @@ Request .. rest_parameters:: parameters.yaml - server_id: server_id_path + - limit: limit_simple + - offset: offset_simple Response -------- diff --git a/api-ref/source/os-volumes.inc b/api-ref/source/os-volumes.inc index a5b195f6e50e..776da44454b0 100644 --- a/api-ref/source/os-volumes.inc +++ b/api-ref/source/os-volumes.inc @@ -26,6 +26,14 @@ Normal response codes: 200 Error response codes: unauthorized(401), forbidden(403) +Request +------- + +.. rest_parameters:: parameters.yaml + + - limit: limit_simple + - offset: offset_simple + Response -------- @@ -126,6 +134,14 @@ Normal response codes: 200 Error response codes: unauthorized(401), forbidden(403) +Request +------- + +.. rest_parameters:: parameters.yaml + + - limit: limit_simple + - offset: offset_simple + Response -------- @@ -237,6 +253,14 @@ Normal response codes: 200 Error response codes: unauthorized(401), forbidden(403) +Request +------- + +.. rest_parameters:: parameters.yaml + + - limit: limit_simple + - offset: offset_simple + Response -------- @@ -315,6 +339,14 @@ Normal response codes: 200 Error response codes: unauthorized(401), forbidden(403) +Request +------- + +.. rest_parameters:: parameters.yaml + + - limit: limit_simple + - offset: offset_simple + Response -------- diff --git a/nova/tests/unit/api/openstack/compute/test_cells.py b/nova/tests/unit/api/openstack/compute/test_cells.py index 30d59b2dc2d4..fd0089770747 100644 --- a/nova/tests/unit/api/openstack/compute/test_cells.py +++ b/nova/tests/unit/api/openstack/compute/test_cells.py @@ -114,6 +114,16 @@ class CellsTestV21(BaseCellsTest): self.assertNotIn('capabilities', cell) self.assertNotIn('password', cell) + def test_index_offset_and_limit(self): + req = self._get_request('cells?offset=1&limit=1') + res_dict = self.controller.index(req) + + self.assertEqual(len(res_dict['cells']), 1) + cell = res_dict['cells'][0] + self.assertEqual(cell['name'], self.fake_cells[1]['name']) + self.assertNotIn('capabilities', cell) + self.assertNotIn('password', cell) + def test_detail(self): req = self._get_request("cells/detail") res_dict = self.controller.detail(req) @@ -124,6 +134,16 @@ class CellsTestV21(BaseCellsTest): self.assertEqual(cell['capabilities'], self.fake_capabilities[i]) self.assertNotIn('password', cell) + def test_detail_offset_and_limit(self): + req = self._get_request("cells/detail?offset=1&limit=1") + res_dict = self.controller.detail(req) + + self.assertEqual(len(res_dict['cells']), 1) + cell = res_dict['cells'][0] + self.assertEqual(cell['name'], self.fake_cells[1]['name']) + self.assertEqual(cell['capabilities'], self.fake_capabilities[1]) + self.assertNotIn('password', cell) + def test_show_bogus_cell_raises(self): req = self._get_request("cells/bogus") self.assertRaises(exc.HTTPNotFound, self.controller.show, req, 'bogus') diff --git a/nova/tests/unit/api/openstack/compute/test_neutron_security_groups.py b/nova/tests/unit/api/openstack/compute/test_neutron_security_groups.py index 66bd3e618fb8..ffce2b08b822 100644 --- a/nova/tests/unit/api/openstack/compute/test_neutron_security_groups.py +++ b/nova/tests/unit/api/openstack/compute/test_neutron_security_groups.py @@ -138,6 +138,13 @@ class TestNeutronSecurityGroupsV21( list_dict = self.controller.index(req) self.assertEqual(len(list_dict['security_groups']), 2) + def test_get_security_group_list_offset_and_limit(self): + path = '/v2/fake/os-security-groups?offset=1&limit=1' + self._create_sg_template().get('security_group') + req = fakes.HTTPRequest.blank(path) + list_dict = self.controller.index(req) + self.assertEqual(len(list_dict['security_groups']), 1) + def test_get_security_group_list_all_tenants(self): pass diff --git a/nova/tests/unit/api/openstack/compute/test_security_groups.py b/nova/tests/unit/api/openstack/compute/test_security_groups.py index e22936a3a331..db0c4e5ceffb 100644 --- a/nova/tests/unit/api/openstack/compute/test_security_groups.py +++ b/nova/tests/unit/api/openstack/compute/test_security_groups.py @@ -317,6 +317,12 @@ class TestSecurityGroupsV21(test.TestCase): self.req, {'security_group': sg}) def test_get_security_group_list(self): + self._test_get_security_group_list() + + def test_get_security_group_list_offset_and_limit(self): + self._test_get_security_group_list(limited=True) + + def _test_get_security_group_list(self, limited=False): groups = [] for i, name in enumerate(['default', 'test']): sg = security_group_template(id=i + 1, @@ -324,7 +330,10 @@ class TestSecurityGroupsV21(test.TestCase): description=name + '-desc', rules=[]) groups.append(sg) - expected = {'security_groups': groups} + if limited: + expected = {'security_groups': [groups[1]]} + else: + expected = {'security_groups': groups} def return_security_groups(context, project_id): return [security_group_db(sg) for sg in groups] @@ -332,7 +341,12 @@ class TestSecurityGroupsV21(test.TestCase): self.stub_out('nova.db.security_group_get_by_project', return_security_groups) - res_dict = self.controller.index(self.req) + path = '/v2/fake/os-security-groups' + if limited: + path += '?offset=1&limit=1' + req = fakes.HTTPRequest.blank(path, use_admin_context=True) + + res_dict = self.controller.index(req) self.assertEqual(res_dict, expected) diff --git a/nova/tests/unit/api/openstack/compute/test_server_groups.py b/nova/tests/unit/api/openstack/compute/test_server_groups.py index f916e6f3d118..0d17600ddac6 100644 --- a/nova/tests/unit/api/openstack/compute/test_server_groups.py +++ b/nova/tests/unit/api/openstack/compute/test_server_groups.py @@ -161,12 +161,16 @@ class ServerGroupTestV21(test.TestCase): ig_uuid = self._create_instance_group(ctx, members) return (ig_uuid, instances, members) + def _test_list_server_group_all(self, api_version='2.1'): + self._test_list_server_group(api_version=api_version, limited=False) + + def _test_list_server_group_offset_and_limit(self, api_version='2.1'): + self._test_list_server_group(api_version=api_version, limited=True) + @mock.patch.object(nova.db, 'instance_group_get_all_by_project_id') @mock.patch.object(nova.db, 'instance_group_get_all') - def _test_list_server_group_all(self, - mock_get_all, - mock_get_by_project, - api_version='2.1'): + def _test_list_server_group(self, mock_get_all, mock_get_by_project, + api_version='2.1', limited=False): policies = ['anti-affinity'] members = [] metadata = {} # always empty @@ -202,8 +206,12 @@ class ServerGroupTestV21(test.TestCase): tenant_groups = [sg2] all_groups = [sg1, sg2] - all = {'server_groups': all_groups} - tenant_specific = {'server_groups': tenant_groups} + if limited: + all = {'server_groups': [sg2]} + tenant_specific = {'server_groups': []} + else: + all = {'server_groups': all_groups} + tenant_specific = {'server_groups': tenant_groups} def return_all_server_groups(): return [server_group_db(sg) for sg in all_groups] @@ -216,7 +224,8 @@ class ServerGroupTestV21(test.TestCase): mock_get_by_project.return_value = return_tenant_server_groups() path = '/os-server-groups?all_projects=True' - + if limited: + path += '&offset=1&limit=1' req = fakes.HTTPRequest.blank(path, version=api_version) admin_req = fakes.HTTPRequest.blank(path, use_admin_context=True, version=api_version) @@ -454,6 +463,9 @@ class ServerGroupTestV21(test.TestCase): def test_list_server_group_all(self): self._test_list_server_group_all(api_version='2.1') + def test_list_server_group_offset_and_limit(self): + self._test_list_server_group_offset_and_limit(api_version='2.1') + def test_list_server_groups_rbac_default(self): # test as admin self.controller.index(self.admin_req) @@ -550,5 +562,8 @@ class ServerGroupTestV213(ServerGroupTestV21): def test_list_server_group_all(self): self._test_list_server_group_all(api_version='2.13') + def test_list_server_group_offset_and_limit(self): + self._test_list_server_group_offset_and_limit(api_version='2.13') + def test_list_server_group_by_tenant(self): self._test_list_server_group_by_tenant(api_version='2.13') diff --git a/nova/tests/unit/api/openstack/compute/test_snapshots.py b/nova/tests/unit/api/openstack/compute/test_snapshots.py index 4bf614b49b04..9b87d5f8917e 100644 --- a/nova/tests/unit/api/openstack/compute/test_snapshots.py +++ b/nova/tests/unit/api/openstack/compute/test_snapshots.py @@ -114,12 +114,31 @@ class SnapshotApiTestV21(test.NoDBTestCase): resp_snapshot = resp_snapshots.pop() self.assertEqual(102, resp_snapshot['id']) + def test_snapshot_detail_offset_and_limit(self): + path = '/v2/fake/os-snapshots/detail?offset=1&limit=1' + req = fakes.HTTPRequest.blank(path) + resp_dict = self.controller.detail(req) + self.assertIn('snapshots', resp_dict) + resp_snapshots = resp_dict['snapshots'] + self.assertEqual(1, len(resp_snapshots)) + + resp_snapshot = resp_snapshots.pop() + self.assertEqual(101, resp_snapshot['id']) + def test_snapshot_index(self): resp_dict = self.controller.index(self.req) self.assertIn('snapshots', resp_dict) resp_snapshots = resp_dict['snapshots'] self.assertEqual(3, len(resp_snapshots)) + def test_snapshot_index_offset_and_limit(self): + path = '/v2/fake/os-snapshots?offset=1&limit=1' + req = fakes.HTTPRequest.blank(path) + resp_dict = self.controller.index(req) + self.assertIn('snapshots', resp_dict) + resp_snapshots = resp_dict['snapshots'] + self.assertEqual(1, len(resp_snapshots)) + class TestSnapshotAPIDeprecation(test.NoDBTestCase): diff --git a/nova/tests/unit/api/openstack/compute/test_virtual_interfaces.py b/nova/tests/unit/api/openstack/compute/test_virtual_interfaces.py index 835086859022..03079f27fe89 100644 --- a/nova/tests/unit/api/openstack/compute/test_virtual_interfaces.py +++ b/nova/tests/unit/api/openstack/compute/test_virtual_interfaces.py @@ -85,6 +85,14 @@ class ServerVirtualInterfaceTestV21(test.NoDBTestCase): res_dict = self.controller.index(req, 'fake_uuid') self.assertEqual(self.expected_response, res_dict) + def test_get_virtual_interfaces_list_offset_and_limit(self): + path = '/v2/fake/os-virtual-interfaces?offset=1&limit=1' + req = fakes.HTTPRequest.blank(path, version=self.wsgi_api_version) + res_dict = self.controller.index(req, 'fake_uuid') + name = 'virtual_interfaces' + limited_response = {name: [self.expected_response[name][1]]} + self.assertEqual(limited_response, res_dict) + def test_vif_instance_not_found(self): self.mox.StubOutWithMock(compute_api.API, 'get') fake_context = context.RequestContext('fake', 'fake')