summaryrefslogtreecommitdiffstats
path: root/keystone-moon/keystone/tests/unit/test_backend.py
diff options
context:
space:
mode:
Diffstat (limited to 'keystone-moon/keystone/tests/unit/test_backend.py')
-rw-r--r--keystone-moon/keystone/tests/unit/test_backend.py533
1 files changed, 490 insertions, 43 deletions
diff --git a/keystone-moon/keystone/tests/unit/test_backend.py b/keystone-moon/keystone/tests/unit/test_backend.py
index 6cf06494..45b8e0b0 100644
--- a/keystone-moon/keystone/tests/unit/test_backend.py
+++ b/keystone-moon/keystone/tests/unit/test_backend.py
@@ -22,6 +22,7 @@ import mock
from oslo_config import cfg
from oslo_utils import timeutils
import six
+from six.moves import range
from testtools import matchers
from keystone.catalog import core
@@ -505,7 +506,7 @@ class IdentityTests(object):
'fake2')
def test_list_role_assignments_unfiltered(self):
- """Test for unfiltered listing role assignments.
+ """Test unfiltered listing of role assignments.
Test Plan:
@@ -533,9 +534,6 @@ class IdentityTests(object):
# First check how many role grants already exist
existing_assignments = len(self.assignment_api.list_role_assignments())
- existing_assignments_for_role = len(
- self.assignment_api.list_role_assignments_for_role(
- role_id='admin'))
# Now create the grants (roles are defined in default_fixtures)
self.assignment_api.create_grant(user_id=new_user['id'],
@@ -573,6 +571,48 @@ class IdentityTests(object):
'role_id': 'admin'},
assignment_list)
+ def test_list_role_assignments_filtered_by_role(self):
+ """Test listing of role assignments filtered by role ID.
+
+ Test Plan:
+
+ - Create a user, group & project
+ - Find how many role assignments already exist (from default
+ fixtures)
+ - Create a grant of each type (user/group on project/domain)
+ - Check that if we list assignments by role_id, then we get back
+ assignments that only contain that role.
+
+ """
+ new_user = {'name': uuid.uuid4().hex, 'password': uuid.uuid4().hex,
+ 'enabled': True, 'domain_id': DEFAULT_DOMAIN_ID}
+ new_user = self.identity_api.create_user(new_user)
+ new_group = {'domain_id': DEFAULT_DOMAIN_ID, 'name': uuid.uuid4().hex}
+ new_group = self.identity_api.create_group(new_group)
+ new_project = {'id': uuid.uuid4().hex,
+ 'name': uuid.uuid4().hex,
+ 'domain_id': DEFAULT_DOMAIN_ID}
+ self.resource_api.create_project(new_project['id'], new_project)
+
+ # First check how many role grants already exist
+ existing_assignments_for_role = len(
+ self.assignment_api.list_role_assignments_for_role(
+ role_id='admin'))
+
+ # Now create the grants (roles are defined in default_fixtures)
+ self.assignment_api.create_grant(user_id=new_user['id'],
+ domain_id=DEFAULT_DOMAIN_ID,
+ role_id='member')
+ self.assignment_api.create_grant(user_id=new_user['id'],
+ project_id=new_project['id'],
+ role_id='other')
+ self.assignment_api.create_grant(group_id=new_group['id'],
+ domain_id=DEFAULT_DOMAIN_ID,
+ role_id='admin')
+ self.assignment_api.create_grant(group_id=new_group['id'],
+ project_id=new_project['id'],
+ role_id='admin')
+
# Read back the list of assignments for just the admin role, checking
# this only goes up by two.
assignment_list = self.assignment_api.list_role_assignments_for_role(
@@ -582,7 +622,7 @@ class IdentityTests(object):
# Now check that each of our two new entries are in the list
self.assertIn(
- {'group_id': new_group['id'], 'domain_id': new_domain['id'],
+ {'group_id': new_group['id'], 'domain_id': DEFAULT_DOMAIN_ID,
'role_id': 'admin'},
assignment_list)
self.assertIn(
@@ -598,8 +638,7 @@ class IdentityTests(object):
def get_member_assignments():
assignments = self.assignment_api.list_role_assignments()
- return filter(lambda x: x['role_id'] == MEMBER_ROLE_ID,
- assignments)
+ return [x for x in assignments if x['role_id'] == MEMBER_ROLE_ID]
orig_member_assignments = get_member_assignments()
@@ -627,8 +666,8 @@ class IdentityTests(object):
expected_member_assignments = orig_member_assignments + [{
'group_id': new_group['id'], 'project_id': new_project['id'],
'role_id': MEMBER_ROLE_ID}]
- self.assertThat(new_member_assignments,
- matchers.Equals(expected_member_assignments))
+ self.assertItemsEqual(expected_member_assignments,
+ new_member_assignments)
def test_list_role_assignments_bad_role(self):
assignment_list = self.assignment_api.list_role_assignments_for_role(
@@ -1976,6 +2015,16 @@ class IdentityTests(object):
project['id'],
project)
+ def test_create_project_invalid_domain_id(self):
+ project = {'id': uuid.uuid4().hex,
+ 'name': uuid.uuid4().hex,
+ 'domain_id': uuid.uuid4().hex,
+ 'enabled': True}
+ self.assertRaises(exception.DomainNotFound,
+ self.resource_api.create_project,
+ project['id'],
+ project)
+
def test_create_user_invalid_enabled_type_string(self):
user = {'name': uuid.uuid4().hex,
'domain_id': DEFAULT_DOMAIN_ID,
@@ -2079,7 +2128,7 @@ class IdentityTests(object):
# Create a project
project = {'id': uuid.uuid4().hex, 'domain_id': DEFAULT_DOMAIN_ID,
'name': uuid.uuid4().hex, 'description': uuid.uuid4().hex,
- 'enabled': True, 'parent_id': None}
+ 'enabled': True, 'parent_id': None, 'is_domain': False}
self.resource_api.create_project(project['id'], project)
# Build driver hints with the project's name and inexistent description
@@ -2131,12 +2180,15 @@ class IdentityTests(object):
self.assertIn(project2['id'], project_ids)
def _create_projects_hierarchy(self, hierarchy_size=2,
- domain_id=DEFAULT_DOMAIN_ID):
+ domain_id=DEFAULT_DOMAIN_ID,
+ is_domain=False):
"""Creates a project hierarchy with specified size.
:param hierarchy_size: the desired hierarchy size, default is 2 -
a project with one child.
:param domain_id: domain where the projects hierarchy will be created.
+ :param is_domain: if the hierarchy will have the is_domain flag active
+ or not.
:returns projects: a list of the projects in the created hierarchy.
@@ -2144,26 +2196,195 @@ class IdentityTests(object):
project_id = uuid.uuid4().hex
project = {'id': project_id,
'description': '',
- 'domain_id': domain_id,
'enabled': True,
'name': uuid.uuid4().hex,
- 'parent_id': None}
+ 'parent_id': None,
+ 'domain_id': domain_id,
+ 'is_domain': is_domain}
self.resource_api.create_project(project_id, project)
projects = [project]
for i in range(1, hierarchy_size):
new_project = {'id': uuid.uuid4().hex,
'description': '',
- 'domain_id': domain_id,
'enabled': True,
'name': uuid.uuid4().hex,
- 'parent_id': project_id}
+ 'parent_id': project_id,
+ 'is_domain': is_domain}
+ new_project['domain_id'] = domain_id
+
self.resource_api.create_project(new_project['id'], new_project)
projects.append(new_project)
project_id = new_project['id']
return projects
+ @tests.skip_if_no_multiple_domains_support
+ def test_create_domain_with_project_api(self):
+ project_id = uuid.uuid4().hex
+ project = {'id': project_id,
+ 'description': '',
+ 'domain_id': DEFAULT_DOMAIN_ID,
+ 'enabled': True,
+ 'name': uuid.uuid4().hex,
+ 'parent_id': None,
+ 'is_domain': True}
+ ref = self.resource_api.create_project(project['id'], project)
+ self.assertTrue(ref['is_domain'])
+ self.assertEqual(DEFAULT_DOMAIN_ID, ref['domain_id'])
+
+ @tests.skip_if_no_multiple_domains_support
+ @test_utils.wip('waiting for projects acting as domains implementation')
+ def test_is_domain_sub_project_has_parent_domain_id(self):
+ project = {'id': uuid.uuid4().hex,
+ 'description': '',
+ 'domain_id': DEFAULT_DOMAIN_ID,
+ 'enabled': True,
+ 'name': uuid.uuid4().hex,
+ 'parent_id': None,
+ 'is_domain': True}
+ self.resource_api.create_project(project['id'], project)
+
+ sub_project_id = uuid.uuid4().hex
+ sub_project = {'id': sub_project_id,
+ 'description': '',
+ 'domain_id': project['id'],
+ 'enabled': True,
+ 'name': uuid.uuid4().hex,
+ 'parent_id': project['id'],
+ 'is_domain': True}
+ ref = self.resource_api.create_project(sub_project['id'], sub_project)
+ self.assertTrue(ref['is_domain'])
+ self.assertEqual(project['id'], ref['parent_id'])
+ self.assertEqual(project['id'], ref['domain_id'])
+
+ @tests.skip_if_no_multiple_domains_support
+ @test_utils.wip('waiting for projects acting as domains implementation')
+ def test_delete_domain_with_project_api(self):
+ project_id = uuid.uuid4().hex
+ project = {'id': project_id,
+ 'description': '',
+ 'domain_id': None,
+ 'enabled': True,
+ 'name': uuid.uuid4().hex,
+ 'parent_id': None,
+ 'is_domain': True}
+ self.resource_api.create_project(project['id'], project)
+
+ # Try to delete is_domain project that is enabled
+ self.assertRaises(exception.ValidationError,
+ self.resource_api.delete_project,
+ project['id'])
+
+ # Disable the project
+ project['enabled'] = False
+ self.resource_api.update_project(project['id'], project)
+
+ # Successfuly delete the project
+ self.resource_api.delete_project(project['id'])
+
+ @tests.skip_if_no_multiple_domains_support
+ @test_utils.wip('waiting for projects acting as domains implementation')
+ def test_create_domain_under_regular_project_hierarchy_fails(self):
+ # Creating a regular project hierarchy. Projects acting as domains
+ # can't have a parent that is a regular project.
+ projects_hierarchy = self._create_projects_hierarchy()
+ parent = projects_hierarchy[1]
+ project_id = uuid.uuid4().hex
+ project = {'id': project_id,
+ 'description': '',
+ 'domain_id': parent['id'],
+ 'enabled': True,
+ 'name': uuid.uuid4().hex,
+ 'parent_id': parent['id'],
+ 'is_domain': True}
+
+ self.assertRaises(exception.ValidationError,
+ self.resource_api.create_project,
+ project['id'], project)
+
+ @tests.skip_if_no_multiple_domains_support
+ @test_utils.wip('waiting for projects acting as domains implementation')
+ def test_create_project_under_domain_hierarchy(self):
+ projects_hierarchy = self._create_projects_hierarchy(is_domain=True)
+ parent = projects_hierarchy[1]
+ project = {'id': uuid.uuid4().hex,
+ 'description': '',
+ 'domain_id': parent['id'],
+ 'enabled': True,
+ 'name': uuid.uuid4().hex,
+ 'parent_id': parent['id'],
+ 'is_domain': False}
+
+ ref = self.resource_api.create_project(project['id'], project)
+ self.assertFalse(ref['is_domain'])
+ self.assertEqual(parent['id'], ref['parent_id'])
+ self.assertEqual(parent['id'], ref['domain_id'])
+
+ def test_create_project_without_is_domain_flag(self):
+ project = {'id': uuid.uuid4().hex,
+ 'description': '',
+ 'domain_id': DEFAULT_DOMAIN_ID,
+ 'enabled': True,
+ 'name': uuid.uuid4().hex,
+ 'parent_id': None}
+
+ ref = self.resource_api.create_project(project['id'], project)
+ # The is_domain flag should be False by default
+ self.assertFalse(ref['is_domain'])
+
+ def test_create_is_domain_project(self):
+ project = {'id': uuid.uuid4().hex,
+ 'description': '',
+ 'domain_id': DEFAULT_DOMAIN_ID,
+ 'enabled': True,
+ 'name': uuid.uuid4().hex,
+ 'parent_id': None,
+ 'is_domain': True}
+
+ ref = self.resource_api.create_project(project['id'], project)
+ self.assertTrue(ref['is_domain'])
+
+ @test_utils.wip('waiting for projects acting as domains implementation')
+ def test_create_project_with_parent_id_and_without_domain_id(self):
+ project = {'id': uuid.uuid4().hex,
+ 'description': '',
+ 'domain_id': None,
+ 'enabled': True,
+ 'name': uuid.uuid4().hex,
+ 'parent_id': None}
+ self.resource_api.create_project(project['id'], project)
+
+ sub_project = {'id': uuid.uuid4().hex,
+ 'description': '',
+ 'enabled': True,
+ 'name': uuid.uuid4().hex,
+ 'parent_id': project['id']}
+ ref = self.resource_api.create_project(sub_project['id'], sub_project)
+
+ # The domain_id should be set to the parent domain_id
+ self.assertEqual(project['domain_id'], ref['domain_id'])
+
+ @test_utils.wip('waiting for projects acting as domains implementation')
+ def test_create_project_with_domain_id_and_without_parent_id(self):
+ project = {'id': uuid.uuid4().hex,
+ 'description': '',
+ 'domain_id': None,
+ 'enabled': True,
+ 'name': uuid.uuid4().hex,
+ 'parent_id': None}
+ self.resource_api.create_project(project['id'], project)
+
+ sub_project = {'id': uuid.uuid4().hex,
+ 'description': '',
+ 'enabled': True,
+ 'domain_id': project['id'],
+ 'name': uuid.uuid4().hex}
+ ref = self.resource_api.create_project(sub_project['id'], sub_project)
+
+ # The parent_id should be set to the domain_id
+ self.assertEqual(ref['parent_id'], project['id'])
+
def test_check_leaf_projects(self):
projects_hierarchy = self._create_projects_hierarchy()
root_project = projects_hierarchy[0]
@@ -2191,7 +2412,8 @@ class IdentityTests(object):
'domain_id': DEFAULT_DOMAIN_ID,
'enabled': True,
'name': uuid.uuid4().hex,
- 'parent_id': project2['id']}
+ 'parent_id': project2['id'],
+ 'is_domain': False}
self.resource_api.create_project(project4['id'], project4)
subtree = self.resource_api.list_projects_in_subtree(project1['id'])
@@ -2208,6 +2430,48 @@ class IdentityTests(object):
subtree = self.resource_api.list_projects_in_subtree(project3['id'])
self.assertEqual(0, len(subtree))
+ def test_list_projects_in_subtree_with_circular_reference(self):
+ project1_id = uuid.uuid4().hex
+ project2_id = uuid.uuid4().hex
+
+ project1 = {'id': project1_id,
+ 'description': '',
+ 'domain_id': DEFAULT_DOMAIN_ID,
+ 'enabled': True,
+ 'name': uuid.uuid4().hex}
+ self.resource_api.create_project(project1['id'], project1)
+
+ project2 = {'id': project2_id,
+ 'description': '',
+ 'domain_id': DEFAULT_DOMAIN_ID,
+ 'enabled': True,
+ 'name': uuid.uuid4().hex,
+ 'parent_id': project1_id}
+ self.resource_api.create_project(project2['id'], project2)
+
+ project1['parent_id'] = project2_id # Adds cyclic reference
+
+ # NOTE(dstanek): The manager does not allow parent_id to be updated.
+ # Instead will directly use the driver to create the cyclic
+ # reference.
+ self.resource_api.driver.update_project(project1_id, project1)
+
+ subtree = self.resource_api.list_projects_in_subtree(project1_id)
+
+ # NOTE(dstanek): If a cyclic refence is detected the code bails
+ # and returns None instead of falling into the infinite
+ # recursion trap.
+ self.assertIsNone(subtree)
+
+ def test_list_projects_in_subtree_invalid_project_id(self):
+ self.assertRaises(exception.ValidationError,
+ self.resource_api.list_projects_in_subtree,
+ None)
+
+ self.assertRaises(exception.ProjectNotFound,
+ self.resource_api.list_projects_in_subtree,
+ uuid.uuid4().hex)
+
def test_list_project_parents(self):
projects_hierarchy = self._create_projects_hierarchy(hierarchy_size=3)
project1 = projects_hierarchy[0]
@@ -2218,7 +2482,8 @@ class IdentityTests(object):
'domain_id': DEFAULT_DOMAIN_ID,
'enabled': True,
'name': uuid.uuid4().hex,
- 'parent_id': project2['id']}
+ 'parent_id': project2['id'],
+ 'is_domain': False}
self.resource_api.create_project(project4['id'], project4)
parents1 = self.resource_api.list_project_parents(project3['id'])
@@ -2232,6 +2497,15 @@ class IdentityTests(object):
parents = self.resource_api.list_project_parents(project1['id'])
self.assertEqual(0, len(parents))
+ def test_list_project_parents_invalid_project_id(self):
+ self.assertRaises(exception.ValidationError,
+ self.resource_api.list_project_parents,
+ None)
+
+ self.assertRaises(exception.ProjectNotFound,
+ self.resource_api.list_project_parents,
+ uuid.uuid4().hex)
+
def test_delete_project_with_role_assignments(self):
tenant = {'id': uuid.uuid4().hex, 'name': uuid.uuid4().hex,
'domain_id': DEFAULT_DOMAIN_ID}
@@ -2812,29 +3086,36 @@ class IdentityTests(object):
'description': '',
'domain_id': DEFAULT_DOMAIN_ID,
'enabled': True,
- 'parent_id': 'fake'}
+ 'parent_id': 'fake',
+ 'is_domain': False}
self.assertRaises(exception.ProjectNotFound,
self.resource_api.create_project,
project['id'],
project)
- def test_create_leaf_project_with_invalid_domain(self):
+ @tests.skip_if_no_multiple_domains_support
+ def test_create_leaf_project_with_different_domain(self):
root_project = {'id': uuid.uuid4().hex,
'name': uuid.uuid4().hex,
'description': '',
'domain_id': DEFAULT_DOMAIN_ID,
'enabled': True,
- 'parent_id': None}
+ 'parent_id': None,
+ 'is_domain': False}
self.resource_api.create_project(root_project['id'], root_project)
+ domain = {'id': uuid.uuid4().hex, 'name': uuid.uuid4().hex,
+ 'enabled': True}
+ self.resource_api.create_domain(domain['id'], domain)
leaf_project = {'id': uuid.uuid4().hex,
'name': uuid.uuid4().hex,
'description': '',
- 'domain_id': 'fake',
+ 'domain_id': domain['id'],
'enabled': True,
- 'parent_id': root_project['id']}
+ 'parent_id': root_project['id'],
+ 'is_domain': False}
- self.assertRaises(exception.ForbiddenAction,
+ self.assertRaises(exception.ValidationError,
self.resource_api.create_project,
leaf_project['id'],
leaf_project)
@@ -2883,17 +3164,19 @@ class IdentityTests(object):
'name': uuid.uuid4().hex,
'domain_id': DEFAULT_DOMAIN_ID,
'enabled': False,
- 'parent_id': None}
+ 'parent_id': None,
+ 'is_domain': False}
self.resource_api.create_project(project1['id'], project1)
project2 = {'id': uuid.uuid4().hex,
'name': uuid.uuid4().hex,
'domain_id': DEFAULT_DOMAIN_ID,
- 'parent_id': project1['id']}
+ 'parent_id': project1['id'],
+ 'is_domain': False}
# It's not possible to create a project under a disabled one in the
# hierarchy
- self.assertRaises(exception.ForbiddenAction,
+ self.assertRaises(exception.ValidationError,
self.resource_api.create_project,
project2['id'],
project2)
@@ -2955,7 +3238,8 @@ class IdentityTests(object):
'id': project_id,
'name': uuid.uuid4().hex,
'domain_id': DEFAULT_DOMAIN_ID,
- 'parent_id': leaf_project['id']}
+ 'parent_id': leaf_project['id'],
+ 'is_domain': False}
self.assertRaises(exception.ForbiddenAction,
self.resource_api.create_project,
project_id,
@@ -2967,7 +3251,8 @@ class IdentityTests(object):
'name': uuid.uuid4().hex,
'domain_id': DEFAULT_DOMAIN_ID,
'enabled': True,
- 'parent_id': None}
+ 'parent_id': None,
+ 'is_domain': False}
self.resource_api.create_project(project['id'], project)
# Add a description attribute.
@@ -2983,7 +3268,8 @@ class IdentityTests(object):
'name': uuid.uuid4().hex,
'domain_id': DEFAULT_DOMAIN_ID,
'enabled': True,
- 'parent_id': None}
+ 'parent_id': None,
+ 'is_domain': False}
self.resource_api.create_project(project['id'], project)
# Add a description attribute.
@@ -3427,8 +3713,7 @@ class IdentityTests(object):
def get_member_assignments():
assignments = self.assignment_api.list_role_assignments()
- return filter(lambda x: x['role_id'] == MEMBER_ROLE_ID,
- assignments)
+ return [x for x in assignments if x['role_id'] == MEMBER_ROLE_ID]
orig_member_assignments = get_member_assignments()
@@ -3662,16 +3947,16 @@ class IdentityTests(object):
domain2 = {'id': uuid.uuid4().hex, 'name': uuid.uuid4().hex}
self.resource_api.create_domain(domain2['id'], domain2)
project1 = {'id': uuid.uuid4().hex, 'name': uuid.uuid4().hex,
- 'domain_id': domain1['id']}
+ 'domain_id': domain1['id'], 'is_domain': False}
project1 = self.resource_api.create_project(project1['id'], project1)
project2 = {'id': uuid.uuid4().hex, 'name': uuid.uuid4().hex,
- 'domain_id': domain1['id']}
+ 'domain_id': domain1['id'], 'is_domain': False}
project2 = self.resource_api.create_project(project2['id'], project2)
project3 = {'id': uuid.uuid4().hex, 'name': uuid.uuid4().hex,
- 'domain_id': domain1['id']}
+ 'domain_id': domain1['id'], 'is_domain': False}
project3 = self.resource_api.create_project(project3['id'], project3)
project4 = {'id': uuid.uuid4().hex, 'name': uuid.uuid4().hex,
- 'domain_id': domain2['id']}
+ 'domain_id': domain2['id'], 'is_domain': False}
project4 = self.resource_api.create_project(project4['id'], project4)
group_list = []
role_list = []
@@ -4291,7 +4576,9 @@ class TrustTests(object):
trust_data = self.trust_api.get_trust(trust_id)
self.assertEqual(new_id, trust_data['id'])
self.trust_api.delete_trust(trust_id)
- self.assertIsNone(self.trust_api.get_trust(trust_id))
+ self.assertRaises(exception.TrustNotFound,
+ self.trust_api.get_trust,
+ trust_id)
def test_delete_trust_not_found(self):
trust_id = uuid.uuid4().hex
@@ -4314,7 +4601,9 @@ class TrustTests(object):
self.assertIsNotNone(trust_data)
self.assertIsNone(trust_data['deleted_at'])
self.trust_api.delete_trust(new_id)
- self.assertIsNone(self.trust_api.get_trust(new_id))
+ self.assertRaises(exception.TrustNotFound,
+ self.trust_api.get_trust,
+ new_id)
deleted_trust = self.trust_api.get_trust(trust_data['id'],
deleted=True)
self.assertEqual(trust_data['id'], deleted_trust['id'])
@@ -4389,7 +4678,9 @@ class TrustTests(object):
self.assertEqual(1, t['remaining_uses'])
self.trust_api.consume_use(trust_data['id'])
# This was the last use, the trust isn't available anymore
- self.assertIsNone(self.trust_api.get_trust(trust_data['id']))
+ self.assertRaises(exception.TrustNotFound,
+ self.trust_api.get_trust,
+ trust_data['id'])
class CatalogTests(object):
@@ -4907,7 +5198,6 @@ class CatalogTests(object):
endpoint = {
'id': uuid.uuid4().hex,
- 'region_id': None,
'service_id': service['id'],
'interface': 'public',
'url': uuid.uuid4().hex,
@@ -5007,6 +5297,29 @@ class CatalogTests(object):
return service_ref, enabled_endpoint_ref, disabled_endpoint_ref
+ def test_list_endpoints(self):
+ service = {
+ 'id': uuid.uuid4().hex,
+ 'type': uuid.uuid4().hex,
+ 'name': uuid.uuid4().hex,
+ 'description': uuid.uuid4().hex,
+ }
+ self.catalog_api.create_service(service['id'], service.copy())
+
+ expected_ids = set([uuid.uuid4().hex for _ in range(3)])
+ for endpoint_id in expected_ids:
+ endpoint = {
+ 'id': endpoint_id,
+ 'region_id': None,
+ 'service_id': service['id'],
+ 'interface': 'public',
+ 'url': uuid.uuid4().hex,
+ }
+ self.catalog_api.create_endpoint(endpoint['id'], endpoint.copy())
+
+ endpoints = self.catalog_api.list_endpoints()
+ self.assertEqual(expected_ids, set(e['id'] for e in endpoints))
+
def test_get_catalog_endpoint_disabled(self):
"""Get back only enabled endpoints when get the v2 catalog."""
@@ -5157,6 +5470,77 @@ class PolicyTests(object):
class InheritanceTests(object):
+ def _test_crud_inherited_and_direct_assignment(self, **kwargs):
+ """Tests inherited and direct assignments for the actor and target
+
+ Ensure it is possible to create both inherited and direct role
+ assignments for the same actor on the same target. The actor and the
+ target are specified in the kwargs as ('user_id' or 'group_id') and
+ ('project_id' or 'domain_id'), respectively.
+
+ """
+
+ # Create a new role to avoid assignments loaded from default fixtures
+ role = {'id': uuid.uuid4().hex, 'name': uuid.uuid4().hex}
+ role = self.role_api.create_role(role['id'], role)
+
+ # Define the common assigment entity
+ assignment_entity = {'role_id': role['id']}
+ assignment_entity.update(kwargs)
+
+ # Define assignments under test
+ direct_assignment_entity = assignment_entity.copy()
+ inherited_assignment_entity = assignment_entity.copy()
+ inherited_assignment_entity['inherited_to_projects'] = 'projects'
+
+ # Create direct assignment and check grants
+ self.assignment_api.create_grant(inherited_to_projects=False,
+ **assignment_entity)
+
+ grants = self.assignment_api.list_role_assignments_for_role(role['id'])
+ self.assertThat(grants, matchers.HasLength(1))
+ self.assertIn(direct_assignment_entity, grants)
+
+ # Now add inherited assignment and check grants
+ self.assignment_api.create_grant(inherited_to_projects=True,
+ **assignment_entity)
+
+ grants = self.assignment_api.list_role_assignments_for_role(role['id'])
+ self.assertThat(grants, matchers.HasLength(2))
+ self.assertIn(direct_assignment_entity, grants)
+ self.assertIn(inherited_assignment_entity, grants)
+
+ # Delete both and check grants
+ self.assignment_api.delete_grant(inherited_to_projects=False,
+ **assignment_entity)
+ self.assignment_api.delete_grant(inherited_to_projects=True,
+ **assignment_entity)
+
+ grants = self.assignment_api.list_role_assignments_for_role(role['id'])
+ self.assertEqual([], grants)
+
+ def test_crud_inherited_and_direct_assignment_for_user_on_domain(self):
+ self._test_crud_inherited_and_direct_assignment(
+ user_id=self.user_foo['id'], domain_id=DEFAULT_DOMAIN_ID)
+
+ def test_crud_inherited_and_direct_assignment_for_group_on_domain(self):
+ group = {'name': uuid.uuid4().hex, 'domain_id': DEFAULT_DOMAIN_ID}
+ group = self.identity_api.create_group(group)
+
+ self._test_crud_inherited_and_direct_assignment(
+ group_id=group['id'], domain_id=DEFAULT_DOMAIN_ID)
+
+ def test_crud_inherited_and_direct_assignment_for_user_on_project(self):
+ self._test_crud_inherited_and_direct_assignment(
+ user_id=self.user_foo['id'], project_id=self.tenant_baz['id'])
+
+ def test_crud_inherited_and_direct_assignment_for_group_on_project(self):
+ group = {'name': uuid.uuid4().hex, 'domain_id': DEFAULT_DOMAIN_ID}
+ group = self.identity_api.create_group(group)
+
+ self._test_crud_inherited_and_direct_assignment(
+ group_id=group['id'], project_id=self.tenant_baz['id'])
+
def test_inherited_role_grants_for_user(self):
"""Test inherited user roles.
@@ -5375,14 +5759,16 @@ class InheritanceTests(object):
'domain_id': DEFAULT_DOMAIN_ID,
'enabled': True,
'name': uuid.uuid4().hex,
- 'parent_id': None}
+ 'parent_id': None,
+ 'is_domain': False}
self.resource_api.create_project(root_project['id'], root_project)
leaf_project = {'id': uuid.uuid4().hex,
'description': '',
'domain_id': DEFAULT_DOMAIN_ID,
'enabled': True,
'name': uuid.uuid4().hex,
- 'parent_id': root_project['id']}
+ 'parent_id': root_project['id'],
+ 'is_domain': False}
self.resource_api.create_project(leaf_project['id'], leaf_project)
user = {'name': uuid.uuid4().hex, 'password': uuid.uuid4().hex,
@@ -5496,14 +5882,16 @@ class InheritanceTests(object):
'domain_id': DEFAULT_DOMAIN_ID,
'enabled': True,
'name': uuid.uuid4().hex,
- 'parent_id': None}
+ 'parent_id': None,
+ 'is_domain': False}
self.resource_api.create_project(root_project['id'], root_project)
leaf_project = {'id': uuid.uuid4().hex,
'description': '',
'domain_id': DEFAULT_DOMAIN_ID,
'enabled': True,
'name': uuid.uuid4().hex,
- 'parent_id': root_project['id']}
+ 'parent_id': root_project['id'],
+ 'is_domain': False}
self.resource_api.create_project(leaf_project['id'], leaf_project)
user = {'name': uuid.uuid4().hex, 'password': uuid.uuid4().hex,
@@ -5663,6 +6051,65 @@ class FilterTests(filtering.FilterTests):
self._delete_test_data('user', user_list)
self._delete_test_data('group', group_list)
+ def _get_user_name_field_size(self):
+ """Return the size of the user name field for the backend.
+
+ Subclasses can override this method to indicate that the user name
+ field is limited in length. The user name is the field used in the test
+ that validates that a filter value works even if it's longer than a
+ field.
+
+ If the backend doesn't limit the value length then return None.
+
+ """
+ return None
+
+ def test_filter_value_wider_than_field(self):
+ # If a filter value is given that's larger than the field in the
+ # backend then no values are returned.
+
+ user_name_field_size = self._get_user_name_field_size()
+
+ if user_name_field_size is None:
+ # The backend doesn't limit the size of the user name, so pass this
+ # test.
+ return
+
+ # Create some users just to make sure would return something if the
+ # filter was ignored.
+ self._create_test_data('user', 2)
+
+ hints = driver_hints.Hints()
+ value = 'A' * (user_name_field_size + 1)
+ hints.add_filter('name', value)
+ users = self.identity_api.list_users(hints=hints)
+ self.assertEqual([], users)
+
+ def test_list_users_in_group_filtered(self):
+ number_of_users = 10
+ user_name_data = {
+ 1: 'Arthur Conan Doyle',
+ 3: 'Arthur Rimbaud',
+ 9: 'Arthur Schopenhauer',
+ }
+ user_list = self._create_test_data(
+ 'user', number_of_users,
+ domain_id=DEFAULT_DOMAIN_ID, name_dict=user_name_data)
+ group = self._create_one_entity('group',
+ DEFAULT_DOMAIN_ID, 'Great Writers')
+ for i in range(7):
+ self.identity_api.add_user_to_group(user_list[i]['id'],
+ group['id'])
+
+ hints = driver_hints.Hints()
+ hints.add_filter('name', 'Arthur', comparator='startswith')
+ users = self.identity_api.list_users_in_group(group['id'], hints=hints)
+ self.assertThat(len(users), matchers.Equals(2))
+ self.assertIn(user_list[1]['id'], [users[0]['id'], users[1]['id']])
+ self.assertIn(user_list[3]['id'], [users[0]['id'], users[1]['id']])
+ self._delete_test_data('user', user_list)
+ self._delete_entity('group')(group['id'])
+
class LimitTests(filtering.FilterTests):
ENTITIES = ['user', 'group', 'project']