Implement HEAD method for all v3 GET actions

Implement the HEAD method for all get-one and list-all operations in the
v3 API (non-extended). While this may never be used by
python-openstackclient, it is useful to operators and application
developers for quickly obtaining metainformation about API resources,
and for "testing hypertext links for validity, accessibility, and
recent modification"[1].

[1] https://www.w3.org/Protocols/rfc2616/rfc2616-sec9.html#sec9.4

Closes-bug: #1370335

Change-Id: Iae26ebea1aa40d3b5c6c676dabe4f60a86a4f99f
This commit is contained in:
Colleen Murphy 2016-03-21 14:15:52 -07:00
parent 8a56c161ee
commit 1d087af001
8 changed files with 131 additions and 79 deletions

View File

@ -63,7 +63,7 @@ class Routers(wsgi.RoutersBase):
self._add_resource( self._add_resource(
mapper, project_controller, mapper, project_controller,
path='/users/{user_id}/projects', path='/users/{user_id}/projects',
get_action='list_user_projects', get_head_action='list_user_projects',
rel=json_home.build_v3_resource_relation('user_projects'), rel=json_home.build_v3_resource_relation('user_projects'),
path_vars={ path_vars={
'user_id': json_home.Parameters.USER_ID, 'user_id': json_home.Parameters.USER_ID,
@ -137,7 +137,7 @@ class Routers(wsgi.RoutersBase):
self._add_resource( self._add_resource(
mapper, grant_controller, mapper, grant_controller,
path='/projects/{project_id}/users/{user_id}/roles', path='/projects/{project_id}/users/{user_id}/roles',
get_action='list_grants', get_head_action='list_grants',
rel=json_home.build_v3_resource_relation('project_user_roles'), rel=json_home.build_v3_resource_relation('project_user_roles'),
path_vars={ path_vars={
'project_id': json_home.Parameters.PROJECT_ID, 'project_id': json_home.Parameters.PROJECT_ID,
@ -146,7 +146,7 @@ class Routers(wsgi.RoutersBase):
self._add_resource( self._add_resource(
mapper, grant_controller, mapper, grant_controller,
path='/projects/{project_id}/groups/{group_id}/roles', path='/projects/{project_id}/groups/{group_id}/roles',
get_action='list_grants', get_head_action='list_grants',
rel=json_home.build_v3_resource_relation('project_group_roles'), rel=json_home.build_v3_resource_relation('project_group_roles'),
path_vars={ path_vars={
'group_id': json_home.Parameters.GROUP_ID, 'group_id': json_home.Parameters.GROUP_ID,
@ -179,7 +179,7 @@ class Routers(wsgi.RoutersBase):
self._add_resource( self._add_resource(
mapper, grant_controller, mapper, grant_controller,
path='/domains/{domain_id}/users/{user_id}/roles', path='/domains/{domain_id}/users/{user_id}/roles',
get_action='list_grants', get_head_action='list_grants',
rel=json_home.build_v3_resource_relation('domain_user_roles'), rel=json_home.build_v3_resource_relation('domain_user_roles'),
path_vars={ path_vars={
'domain_id': json_home.Parameters.DOMAIN_ID, 'domain_id': json_home.Parameters.DOMAIN_ID,
@ -188,7 +188,7 @@ class Routers(wsgi.RoutersBase):
self._add_resource( self._add_resource(
mapper, grant_controller, mapper, grant_controller,
path='/domains/{domain_id}/groups/{group_id}/roles', path='/domains/{domain_id}/groups/{group_id}/roles',
get_action='list_grants', get_head_action='list_grants',
rel=json_home.build_v3_resource_relation('domain_group_roles'), rel=json_home.build_v3_resource_relation('domain_group_roles'),
path_vars={ path_vars={
'domain_id': json_home.Parameters.DOMAIN_ID, 'domain_id': json_home.Parameters.DOMAIN_ID,
@ -198,7 +198,7 @@ class Routers(wsgi.RoutersBase):
self._add_resource( self._add_resource(
mapper, controllers.RoleAssignmentV3(), mapper, controllers.RoleAssignmentV3(),
path='/role_assignments', path='/role_assignments',
get_action='list_role_assignments_wrapper', get_head_action='list_role_assignments_wrapper',
rel=json_home.build_v3_resource_relation('role_assignments')) rel=json_home.build_v3_resource_relation('role_assignments'))
if CONF.os_inherit.enabled: if CONF.os_inherit.enabled:

View File

@ -44,12 +44,12 @@ class Router(wsgi.ComposableRouter):
collection_path, collection_path,
controller=self.controller, controller=self.controller,
action=self.method_template % 'list_%s' % self.collection_key, action=self.method_template % 'list_%s' % self.collection_key,
conditions=dict(method=['GET'])) conditions=dict(method=['GET', 'HEAD']))
mapper.connect( mapper.connect(
entity_path, entity_path,
controller=self.controller, controller=self.controller,
action=self.method_template % 'get_%s' % self.key, action=self.method_template % 'get_%s' % self.key,
conditions=dict(method=['GET'])) conditions=dict(method=['GET', 'HEAD']))
mapper.connect( mapper.connect(
entity_path, entity_path,
controller=self.controller, controller=self.controller,

View File

@ -50,7 +50,7 @@ class Routers(wsgi.RoutersBase):
self._add_resource( self._add_resource(
mapper, user_controller, mapper, user_controller,
path='/groups/{group_id}/users', path='/groups/{group_id}/users',
get_action='list_users_in_group', get_head_action='list_users_in_group',
rel=json_home.build_v3_resource_relation('group_users'), rel=json_home.build_v3_resource_relation('group_users'),
path_vars={ path_vars={
'group_id': json_home.Parameters.GROUP_ID, 'group_id': json_home.Parameters.GROUP_ID,
@ -77,7 +77,7 @@ class Routers(wsgi.RoutersBase):
self._add_resource( self._add_resource(
mapper, group_controller, mapper, group_controller,
path='/users/{user_id}/groups', path='/users/{user_id}/groups',
get_action='list_groups_for_user', get_head_action='list_groups_for_user',
rel=json_home.build_v3_resource_relation('user_groups'), rel=json_home.build_v3_resource_relation('user_groups'),
path_vars={ path_vars={
'user_id': json_home.Parameters.USER_ID, 'user_id': json_home.Parameters.USER_ID,

View File

@ -51,18 +51,21 @@ class AssignmentTestCase(test_v3.RestfulTestCase,
self.post('/roles', body={'role': {}}, self.post('/roles', body={'role': {}},
expected_status=http_client.BAD_REQUEST) expected_status=http_client.BAD_REQUEST)
def test_list_roles(self): def test_list_head_roles(self):
"""Call ``GET /roles``.""" """Call ``GET & HEAD /roles``."""
resource_url = '/roles' resource_url = '/roles'
r = self.get(resource_url) r = self.get(resource_url)
self.assertValidRoleListResponse(r, ref=self.role, self.assertValidRoleListResponse(r, ref=self.role,
resource_url=resource_url) resource_url=resource_url)
self.head(resource_url, expected_status=http_client.OK)
def test_get_role(self): def test_get_head_role(self):
"""Call ``GET /roles/{role_id}``.""" """Call ``GET & HEAD /roles/{role_id}``."""
r = self.get('/roles/%(role_id)s' % { resource_url = '/roles/%(role_id)s' % {
'role_id': self.role_id}) 'role_id': self.role_id}
r = self.get(resource_url)
self.assertValidRoleResponse(r, self.role) self.assertValidRoleResponse(r, self.role)
self.head(resource_url, expected_status=http_client.OK)
def test_update_role(self): def test_update_role(self):
"""Call ``PATCH /roles/{role_id}``.""" """Call ``PATCH /roles/{role_id}``."""
@ -115,11 +118,13 @@ class AssignmentTestCase(test_v3.RestfulTestCase,
self.assertValidRoleListResponse(r, ref=role, self.assertValidRoleListResponse(r, ref=role,
resource_url=collection_url, resource_url=collection_url,
expected_length=2) expected_length=2)
self.head(collection_url, expected_status=http_client.OK)
self.delete(member_url) self.delete(member_url)
r = self.get(collection_url) r = self.get(collection_url)
self.assertValidRoleListResponse(r, ref=self.role, expected_length=1) self.assertValidRoleListResponse(r, ref=self.role, expected_length=1)
self.assertIn(collection_url, r.result['links']['self']) self.assertIn(collection_url, r.result['links']['self'])
self.head(collection_url, expected_status=http_client.OK)
def test_crud_user_project_role_grants_no_user(self): def test_crud_user_project_role_grants_no_user(self):
"""Grant role on a project to a user that doesn't exist. """Grant role on a project to a user that doesn't exist.
@ -153,11 +158,13 @@ class AssignmentTestCase(test_v3.RestfulTestCase,
r = self.get(collection_url) r = self.get(collection_url)
self.assertValidRoleListResponse(r, ref=self.role, self.assertValidRoleListResponse(r, ref=self.role,
resource_url=collection_url) resource_url=collection_url)
self.head(collection_url, expected_status=http_client.OK)
self.delete(member_url) self.delete(member_url)
r = self.get(collection_url) r = self.get(collection_url)
self.assertValidRoleListResponse(r, expected_length=0, self.assertValidRoleListResponse(r, expected_length=0,
resource_url=collection_url) resource_url=collection_url)
self.head(collection_url, expected_status=http_client.OK)
def test_crud_user_domain_role_grants_no_user(self): def test_crud_user_domain_role_grants_no_user(self):
"""Grant role on a domain to a user that doesn't exist. """Grant role on a domain to a user that doesn't exist.
@ -191,11 +198,13 @@ class AssignmentTestCase(test_v3.RestfulTestCase,
r = self.get(collection_url) r = self.get(collection_url)
self.assertValidRoleListResponse(r, ref=self.role, self.assertValidRoleListResponse(r, ref=self.role,
resource_url=collection_url) resource_url=collection_url)
self.head(collection_url, expected_status=http_client.OK)
self.delete(member_url) self.delete(member_url)
r = self.get(collection_url) r = self.get(collection_url)
self.assertValidRoleListResponse(r, expected_length=0, self.assertValidRoleListResponse(r, expected_length=0,
resource_url=collection_url) resource_url=collection_url)
self.head(collection_url, expected_status=http_client.OK)
def test_crud_group_project_role_grants_no_group(self): def test_crud_group_project_role_grants_no_group(self):
"""Grant role on a project to a group that doesn't exist. """Grant role on a project to a group that doesn't exist.
@ -230,11 +239,13 @@ class AssignmentTestCase(test_v3.RestfulTestCase,
r = self.get(collection_url) r = self.get(collection_url)
self.assertValidRoleListResponse(r, ref=self.role, self.assertValidRoleListResponse(r, ref=self.role,
resource_url=collection_url) resource_url=collection_url)
self.head(collection_url, expected_status=http_client.OK)
self.delete(member_url) self.delete(member_url)
r = self.get(collection_url) r = self.get(collection_url)
self.assertValidRoleListResponse(r, expected_length=0, self.assertValidRoleListResponse(r, expected_length=0,
resource_url=collection_url) resource_url=collection_url)
self.head(collection_url, expected_status=http_client.OK)
def test_crud_group_domain_role_grants_no_group(self): def test_crud_group_domain_role_grants_no_group(self):
"""Grant role on a domain to a group that doesn't exist. """Grant role on a domain to a group that doesn't exist.
@ -457,8 +468,8 @@ class AssignmentTestCase(test_v3.RestfulTestCase,
# Role Assignments tests # Role Assignments tests
def test_get_role_assignments(self): def test_get_head_role_assignments(self):
"""Call ``GET /role_assignments``. """Call ``GET & HEAD /role_assignments``.
The sample data set up already has a user, group and project The sample data set up already has a user, group and project
that is part of self.domain. We use these plus a new user that is part of self.domain. We use these plus a new user
@ -493,6 +504,7 @@ class AssignmentTestCase(test_v3.RestfulTestCase,
r = self.get(collection_url) r = self.get(collection_url)
self.assertValidRoleAssignmentListResponse(r, self.assertValidRoleAssignmentListResponse(r,
resource_url=collection_url) resource_url=collection_url)
self.head(collection_url, expected_status=http_client.OK)
existing_assignments = len(r.result.get('role_assignments')) existing_assignments = len(r.result.get('role_assignments'))
# Now add one of each of the four types of assignment, making sure # Now add one of each of the four types of assignment, making sure
@ -507,6 +519,7 @@ class AssignmentTestCase(test_v3.RestfulTestCase,
expected_length=existing_assignments + 1, expected_length=existing_assignments + 1,
resource_url=collection_url) resource_url=collection_url)
self.assertRoleAssignmentInListResponse(r, gd_entity) self.assertRoleAssignmentInListResponse(r, gd_entity)
self.head(collection_url, expected_status=http_client.OK)
ud_entity = self.build_role_assignment_entity(domain_id=self.domain_id, ud_entity = self.build_role_assignment_entity(domain_id=self.domain_id,
user_id=user1['id'], user_id=user1['id'],
@ -518,6 +531,7 @@ class AssignmentTestCase(test_v3.RestfulTestCase,
expected_length=existing_assignments + 2, expected_length=existing_assignments + 2,
resource_url=collection_url) resource_url=collection_url)
self.assertRoleAssignmentInListResponse(r, ud_entity) self.assertRoleAssignmentInListResponse(r, ud_entity)
self.head(collection_url, expected_status=http_client.OK)
gp_entity = self.build_role_assignment_entity( gp_entity = self.build_role_assignment_entity(
project_id=self.project_id, group_id=self.group_id, project_id=self.project_id, group_id=self.group_id,
@ -529,6 +543,7 @@ class AssignmentTestCase(test_v3.RestfulTestCase,
expected_length=existing_assignments + 3, expected_length=existing_assignments + 3,
resource_url=collection_url) resource_url=collection_url)
self.assertRoleAssignmentInListResponse(r, gp_entity) self.assertRoleAssignmentInListResponse(r, gp_entity)
self.head(collection_url, expected_status=http_client.OK)
up_entity = self.build_role_assignment_entity( up_entity = self.build_role_assignment_entity(
project_id=self.project_id, user_id=user1['id'], project_id=self.project_id, user_id=user1['id'],
@ -540,6 +555,7 @@ class AssignmentTestCase(test_v3.RestfulTestCase,
expected_length=existing_assignments + 4, expected_length=existing_assignments + 4,
resource_url=collection_url) resource_url=collection_url)
self.assertRoleAssignmentInListResponse(r, up_entity) self.assertRoleAssignmentInListResponse(r, up_entity)
self.head(collection_url, expected_status=http_client.OK)
# Now delete the four we added and make sure they are removed # Now delete the four we added and make sure they are removed
# from the collection. # from the collection.
@ -557,6 +573,7 @@ class AssignmentTestCase(test_v3.RestfulTestCase,
self.assertRoleAssignmentNotInListResponse(r, ud_entity) self.assertRoleAssignmentNotInListResponse(r, ud_entity)
self.assertRoleAssignmentNotInListResponse(r, gp_entity) self.assertRoleAssignmentNotInListResponse(r, gp_entity)
self.assertRoleAssignmentNotInListResponse(r, up_entity) self.assertRoleAssignmentNotInListResponse(r, up_entity)
self.head(collection_url, expected_status=http_client.OK)
def test_get_effective_role_assignments(self): def test_get_effective_role_assignments(self):
"""Call ``GET /role_assignments?effective``. """Call ``GET /role_assignments?effective``.
@ -2808,7 +2825,7 @@ class ListUserProjectsTestCase(test_v3.RestfulTestCase):
self.roles.append(role) self.roles.append(role)
self.users.append(user) self.users.append(user)
def test_list_all(self): def test_list_head_all(self):
for i in range(len(self.users)): for i in range(len(self.users)):
user = self.users[i] user = self.users[i]
auth = self.auths[i] auth = self.auths[i]
@ -2818,6 +2835,7 @@ class ListUserProjectsTestCase(test_v3.RestfulTestCase):
projects_result = result.json['projects'] projects_result = result.json['projects']
self.assertEqual(1, len(projects_result)) self.assertEqual(1, len(projects_result))
self.assertEqual(self.projects[i]['id'], projects_result[0]['id']) self.assertEqual(self.projects[i]['id'], projects_result[0]['id'])
self.head(url, auth=auth, expected_status=http_client.OK)
def test_list_enabled(self): def test_list_enabled(self):
for i in range(len(self.users)): for i in range(len(self.users)):

View File

@ -161,10 +161,12 @@ class CatalogTestCase(test_v3.RestfulTestCase):
body={'region': ref}, body={'region': ref},
expected_status=http_client.BAD_REQUEST) expected_status=http_client.BAD_REQUEST)
def test_list_regions(self): def test_list_head_regions(self):
"""Call ``GET /regions``.""" """Call ``GET & HEAD /regions``."""
r = self.get('/regions') resource_url = '/regions'
r = self.get(resource_url)
self.assertValidRegionListResponse(r, ref=self.region) self.assertValidRegionListResponse(r, ref=self.region)
self.head(resource_url, expected_status=http_client.OK)
def _create_region_with_parent_id(self, parent_id=None): def _create_region_with_parent_id(self, parent_id=None):
ref = unit.new_region_ref(parent_region_id=parent_id) ref = unit.new_region_ref(parent_region_id=parent_id)
@ -185,11 +187,13 @@ class CatalogTestCase(test_v3.RestfulTestCase):
for region in r.result['regions']: for region in r.result['regions']:
self.assertEqual(parent_id, region['parent_region_id']) self.assertEqual(parent_id, region['parent_region_id'])
def test_get_region(self): def test_get_head_region(self):
"""Call ``GET /regions/{region_id}``.""" """Call ``GET & HEAD /regions/{region_id}``."""
r = self.get('/regions/%(region_id)s' % { resource_url = '/regions/%(region_id)s' % {
'region_id': self.region_id}) 'region_id': self.region_id}
r = self.get(resource_url)
self.assertValidRegionResponse(r, self.region) self.assertValidRegionResponse(r, self.region)
self.head(resource_url, expected_status=http_client.OK)
def test_update_region(self): def test_update_region(self):
"""Call ``PATCH /regions/{region_id}``.""" """Call ``PATCH /regions/{region_id}``."""
@ -308,10 +312,12 @@ class CatalogTestCase(test_v3.RestfulTestCase):
self.post('/services', body={'service': ref}, self.post('/services', body={'service': ref},
expected_status=http_client.BAD_REQUEST) expected_status=http_client.BAD_REQUEST)
def test_list_services(self): def test_list_head_services(self):
"""Call ``GET /services``.""" """Call ``GET & HEAD /services``."""
r = self.get('/services') resource_url = '/services'
r = self.get(resource_url)
self.assertValidServiceListResponse(r, ref=self.service) self.assertValidServiceListResponse(r, ref=self.service)
self.head(resource_url, expected_status=http_client.OK)
def _create_random_service(self): def _create_random_service(self):
ref = unit.new_service_ref() ref = unit.new_service_ref()
@ -354,11 +360,13 @@ class CatalogTestCase(test_v3.RestfulTestCase):
filtered_service = filtered_service_list[0] filtered_service = filtered_service_list[0]
self.assertEqual(target_ref['name'], filtered_service['name']) self.assertEqual(target_ref['name'], filtered_service['name'])
def test_get_service(self): def test_get_head_service(self):
"""Call ``GET /services/{service_id}``.""" """Call ``GET & HEAD /services/{service_id}``."""
r = self.get('/services/%(service_id)s' % { resource_url = '/services/%(service_id)s' % {
'service_id': self.service_id}) 'service_id': self.service_id}
r = self.get(resource_url)
self.assertValidServiceResponse(r, self.service) self.assertValidServiceResponse(r, self.service)
self.head(resource_url, expected_status=http_client.OK)
def test_update_service(self): def test_update_service(self):
"""Call ``PATCH /services/{service_id}``.""" """Call ``PATCH /services/{service_id}``."""
@ -376,10 +384,12 @@ class CatalogTestCase(test_v3.RestfulTestCase):
# endpoint crud tests # endpoint crud tests
def test_list_endpoints(self): def test_list_head_endpoints(self):
"""Call ``GET /endpoints``.""" """Call ``GET & HEAD /endpoints``."""
r = self.get('/endpoints') resource_url = '/endpoints'
r = self.get(resource_url)
self.assertValidEndpointListResponse(r, ref=self.endpoint) self.assertValidEndpointListResponse(r, ref=self.endpoint)
self.head(resource_url, expected_status=http_client.OK)
def _create_random_endpoint(self, interface='public', def _create_random_endpoint(self, interface='public',
parent_region_id=None): parent_region_id=None):
@ -591,12 +601,13 @@ class CatalogTestCase(test_v3.RestfulTestCase):
self.post('/endpoints', body={'endpoint': ref}, self.post('/endpoints', body={'endpoint': ref},
expected_status=http_client.BAD_REQUEST) expected_status=http_client.BAD_REQUEST)
def test_get_endpoint(self): def test_get_head_endpoint(self):
"""Call ``GET /endpoints/{endpoint_id}``.""" """Call ``GET & HEAD /endpoints/{endpoint_id}``."""
r = self.get( resource_url = '/endpoints/%(endpoint_id)s' % {
'/endpoints/%(endpoint_id)s' % { 'endpoint_id': self.endpoint_id}
'endpoint_id': self.endpoint_id}) r = self.get(resource_url)
self.assertValidEndpointResponse(r, self.endpoint) self.assertValidEndpointResponse(r, self.endpoint)
self.head(resource_url, expected_status=http_client.OK)
def test_update_endpoint(self): def test_update_endpoint(self):
"""Call ``PATCH /endpoints/{endpoint_id}``.""" """Call ``PATCH /endpoints/{endpoint_id}``."""

View File

@ -219,12 +219,13 @@ class IdentityTestCase(test_v3.RestfulTestCase):
self.post('/users', body={'user': {}}, self.post('/users', body={'user': {}},
expected_status=http_client.BAD_REQUEST) expected_status=http_client.BAD_REQUEST)
def test_list_users(self): def test_list_head_users(self):
"""Call ``GET /users``.""" """Call ``GET & HEAD /users``."""
resource_url = '/users' resource_url = '/users'
r = self.get(resource_url) r = self.get(resource_url)
self.assertValidUserListResponse(r, ref=self.user, self.assertValidUserListResponse(r, ref=self.user,
resource_url=resource_url) resource_url=resource_url)
self.head(resource_url, expected_status=http_client.OK)
def test_list_users_with_multiple_backends(self): def test_list_users_with_multiple_backends(self):
"""Call ``GET /users`` when multiple backends is enabled. """Call ``GET /users`` when multiple backends is enabled.
@ -291,11 +292,13 @@ class IdentityTestCase(test_v3.RestfulTestCase):
self.assertValidUserListResponse(r, ref=user, self.assertValidUserListResponse(r, ref=user,
resource_url=resource_url) resource_url=resource_url)
def test_get_user(self): def test_get_head_user(self):
"""Call ``GET /users/{user_id}``.""" """Call ``GET & HEAD /users/{user_id}``."""
r = self.get('/users/%(user_id)s' % { resource_url = '/users/%(user_id)s' % {
'user_id': self.user['id']}) 'user_id': self.user['id']}
r = self.get(resource_url)
self.assertValidUserResponse(r, self.user) self.assertValidUserResponse(r, self.user)
self.head(resource_url, expected_status=http_client.OK)
def test_get_user_with_default_project(self): def test_get_user_with_default_project(self):
"""Call ``GET /users/{user_id}`` making sure of default_project_id.""" """Call ``GET /users/{user_id}`` making sure of default_project_id."""
@ -310,8 +313,8 @@ class IdentityTestCase(test_v3.RestfulTestCase):
self.put('/groups/%(group_id)s/users/%(user_id)s' % { self.put('/groups/%(group_id)s/users/%(user_id)s' % {
'group_id': self.group_id, 'user_id': self.user['id']}) 'group_id': self.group_id, 'user_id': self.user['id']})
def test_list_groups_for_user(self): def test_list_head_groups_for_user(self):
"""Call ``GET /users/{user_id}/groups``.""" """Call ``GET & HEAD /users/{user_id}/groups``."""
user1 = unit.create_user(self.identity_api, user1 = unit.create_user(self.identity_api,
domain_id=self.domain['id']) domain_id=self.domain['id'])
user2 = unit.create_user(self.identity_api, user2 = unit.create_user(self.identity_api,
@ -331,6 +334,7 @@ class IdentityTestCase(test_v3.RestfulTestCase):
r = self.get(resource_url, auth=auth) r = self.get(resource_url, auth=auth)
self.assertValidGroupListResponse(r, ref=self.group, self.assertValidGroupListResponse(r, ref=self.group,
resource_url=resource_url) resource_url=resource_url)
self.head(resource_url, auth=auth, expected_status=http_client.OK)
# Administrator is allowed to list others' groups # Administrator is allowed to list others' groups
resource_url = ('/users/%(user_id)s/groups' % resource_url = ('/users/%(user_id)s/groups' %
@ -338,14 +342,18 @@ class IdentityTestCase(test_v3.RestfulTestCase):
r = self.get(resource_url) r = self.get(resource_url)
self.assertValidGroupListResponse(r, ref=self.group, self.assertValidGroupListResponse(r, ref=self.group,
resource_url=resource_url) resource_url=resource_url)
self.head(resource_url, expected_status=http_client.OK)
# Ordinary users should not be allowed to list other's groups # Ordinary users should not be allowed to list other's groups
auth = self.build_authentication_request( auth = self.build_authentication_request(
user_id=user2['id'], user_id=user2['id'],
password=user2['password']) password=user2['password'])
r = self.get('/users/%(user_id)s/groups' % { resource_url = '/users/%(user_id)s/groups' % {
'user_id': user1['id']}, auth=auth, 'user_id': user1['id']}
expected_status=exception.ForbiddenAction.code) self.get(resource_url, auth=auth,
expected_status=exception.ForbiddenAction.code)
self.head(resource_url, auth=auth,
expected_status=exception.ForbiddenAction.code)
def test_check_user_in_group(self): def test_check_user_in_group(self):
"""Call ``HEAD /groups/{group_id}/users/{user_id}``.""" """Call ``HEAD /groups/{group_id}/users/{user_id}``."""
@ -354,8 +362,8 @@ class IdentityTestCase(test_v3.RestfulTestCase):
self.head('/groups/%(group_id)s/users/%(user_id)s' % { self.head('/groups/%(group_id)s/users/%(user_id)s' % {
'group_id': self.group_id, 'user_id': self.user['id']}) 'group_id': self.group_id, 'user_id': self.user['id']})
def test_list_users_in_group(self): def test_list_head_users_in_group(self):
"""Call ``GET /groups/{group_id}/users``.""" """Call ``GET & HEAD /groups/{group_id}/users``."""
self.put('/groups/%(group_id)s/users/%(user_id)s' % { self.put('/groups/%(group_id)s/users/%(user_id)s' % {
'group_id': self.group_id, 'user_id': self.user['id']}) 'group_id': self.group_id, 'user_id': self.user['id']})
resource_url = ('/groups/%(group_id)s/users' % resource_url = ('/groups/%(group_id)s/users' %
@ -365,6 +373,7 @@ class IdentityTestCase(test_v3.RestfulTestCase):
resource_url=resource_url) resource_url=resource_url)
self.assertIn('/groups/%(group_id)s/users' % { self.assertIn('/groups/%(group_id)s/users' % {
'group_id': self.group_id}, r.result['links']['self']) 'group_id': self.group_id}, r.result['links']['self'])
self.head(resource_url, expected_status=http_client.OK)
def test_remove_user_from_group(self): def test_remove_user_from_group(self):
"""Call ``DELETE /groups/{group_id}/users/{user_id}``.""" """Call ``DELETE /groups/{group_id}/users/{user_id}``."""
@ -515,18 +524,21 @@ class IdentityTestCase(test_v3.RestfulTestCase):
self.post('/groups', body={'group': {}}, self.post('/groups', body={'group': {}},
expected_status=http_client.BAD_REQUEST) expected_status=http_client.BAD_REQUEST)
def test_list_groups(self): def test_list_head_groups(self):
"""Call ``GET /groups``.""" """Call ``GET & HEAD /groups``."""
resource_url = '/groups' resource_url = '/groups'
r = self.get(resource_url) r = self.get(resource_url)
self.assertValidGroupListResponse(r, ref=self.group, self.assertValidGroupListResponse(r, ref=self.group,
resource_url=resource_url) resource_url=resource_url)
self.head(resource_url, expected_status=http_client.OK)
def test_get_group(self): def test_get_head_group(self):
"""Call ``GET /groups/{group_id}``.""" """Call ``GET & HEAD /groups/{group_id}``."""
r = self.get('/groups/%(group_id)s' % { resource_url = '/groups/%(group_id)s' % {
'group_id': self.group_id}) 'group_id': self.group_id}
r = self.get(resource_url)
self.assertValidGroupResponse(r, self.group) self.assertValidGroupResponse(r, self.group)
self.head(resource_url, expected_status=http_client.OK)
def test_update_group(self): def test_update_group(self):
"""Call ``PATCH /groups/{group_id}``.""" """Call ``PATCH /groups/{group_id}``."""

View File

@ -15,6 +15,8 @@
import json import json
import uuid import uuid
from six.moves import http_client
from keystone.tests import unit from keystone.tests import unit
from keystone.tests.unit import test_v3 from keystone.tests.unit import test_v3
@ -38,16 +40,20 @@ class PolicyTestCase(test_v3.RestfulTestCase):
r = self.post('/policies', body={'policy': ref}) r = self.post('/policies', body={'policy': ref})
return self.assertValidPolicyResponse(r, ref) return self.assertValidPolicyResponse(r, ref)
def test_list_policies(self): def test_list_head_policies(self):
"""Call ``GET /policies``.""" """Call ``GET & HEAD /policies``."""
r = self.get('/policies') resource_url = '/policies'
r = self.get(resource_url)
self.assertValidPolicyListResponse(r, ref=self.policy) self.assertValidPolicyListResponse(r, ref=self.policy)
self.head(resource_url, expected_status=http_client.OK)
def test_get_policy(self): def test_get_head_policy(self):
"""Call ``GET /policies/{policy_id}``.""" """Call ``GET & HEAD /policies/{policy_id}``."""
r = self.get( resource_url = ('/policies/%(policy_id)s' %
'/policies/%(policy_id)s' % {'policy_id': self.policy_id}) {'policy_id': self.policy_id})
r = self.get(resource_url)
self.assertValidPolicyResponse(r, self.policy) self.assertValidPolicyResponse(r, self.policy)
self.head(resource_url, expected_status=http_client.OK)
def test_update_policy(self): def test_update_policy(self):
"""Call ``PATCH /policies/{policy_id}``.""" """Call ``PATCH /policies/{policy_id}``."""

View File

@ -129,18 +129,21 @@ class ResourceTestCase(test_v3.RestfulTestCase,
self.assertValidDomainResponse(r) self.assertValidDomainResponse(r)
self.assertIsNotNone(r.result['domain']) self.assertIsNotNone(r.result['domain'])
def test_list_domains(self): def test_list_head_domains(self):
"""Call ``GET /domains``.""" """Call ``GET & HEAD /domains``."""
resource_url = '/domains' resource_url = '/domains'
r = self.get(resource_url) r = self.get(resource_url)
self.assertValidDomainListResponse(r, ref=self.domain, self.assertValidDomainListResponse(r, ref=self.domain,
resource_url=resource_url) resource_url=resource_url)
self.head(resource_url, expected_status=http_client.OK)
def test_get_domain(self): def test_get_head_domain(self):
"""Call ``GET /domains/{domain_id}``.""" """Call ``GET /domains/{domain_id}``."""
r = self.get('/domains/%(domain_id)s' % { resource_url = '/domains/%(domain_id)s' % {
'domain_id': self.domain_id}) 'domain_id': self.domain_id}
r = self.get(resource_url)
self.assertValidDomainResponse(r, self.domain) self.assertValidDomainResponse(r, self.domain)
self.head(resource_url, expected_status=http_client.OK)
def test_update_domain(self): def test_update_domain(self):
"""Call ``PATCH /domains/{domain_id}``.""" """Call ``PATCH /domains/{domain_id}``."""
@ -541,12 +544,13 @@ class ResourceTestCase(test_v3.RestfulTestCase,
# Project CRUD tests # Project CRUD tests
def test_list_projects(self): def test_list_head_projects(self):
"""Call ``GET /projects``.""" """Call ``GET & HEAD /projects``."""
resource_url = '/projects' resource_url = '/projects'
r = self.get(resource_url) r = self.get(resource_url)
self.assertValidProjectListResponse(r, ref=self.project, self.assertValidProjectListResponse(r, ref=self.project,
resource_url=resource_url) resource_url=resource_url)
self.head(resource_url, expected_status=http_client.OK)
def test_create_project(self): def test_create_project(self):
"""Call ``POST /projects``.""" """Call ``POST /projects``."""
@ -752,12 +756,13 @@ class ResourceTestCase(test_v3.RestfulTestCase,
"""Call ``POST /projects``.""" """Call ``POST /projects``."""
self._create_projects_hierarchy() self._create_projects_hierarchy()
def test_get_project(self): def test_get_head_project(self):
"""Call ``GET /projects/{project_id}``.""" """Call ``GET & HEAD /projects/{project_id}``."""
r = self.get( resource_url = '/projects/%(project_id)s' % {
'/projects/%(project_id)s' % { 'project_id': self.project_id}
'project_id': self.project_id}) r = self.get(resource_url)
self.assertValidProjectResponse(r, self.project) self.assertValidProjectResponse(r, self.project)
self.head(resource_url, expected_status=http_client.OK)
def test_get_project_with_parents_as_list_with_invalid_id(self): def test_get_project_with_parents_as_list_with_invalid_id(self):
"""Call ``GET /projects/{project_id}?parents_as_list``.""" """Call ``GET /projects/{project_id}?parents_as_list``."""