Add tests in preparation of projects acting as a domain

In subsequent patches projects will start acting as domains.
This patch adds REST level tests, protected by the wip decorator,
that will validate the external view of projects acting as domains.

This patch also modifies the unit.new_project_ref() test helper to
better represent that parent_id is an optional parameter for
1st level projects (since their parent is defined by their
domain_id). This will allow us to better test the various
mixtures of domain_id and parent_id in future patches. This
exposed a number of test cases which did not allow for the
fact that parent_id may not have been set by new_project_ref().

Co-Authored-By: Henrique Truta <henrique@lsd.ufcg.edu.br>
Co-Authored-By: Rodrigo Duarte <rodrigods@lsd.ufcg.edu.br>

Partially implements: blueprint reseller

Change-Id: Ibd4b6ca35746ad497523c01352b7b6b985ac8a7f
This commit is contained in:
Henry Nash 2016-01-26 03:38:15 +00:00 committed by Henrique Truta
parent 72faa02851
commit de40ce1e92
6 changed files with 138 additions and 46 deletions

View File

@ -307,16 +307,19 @@ def new_domain_ref(**kwargs):
return ref
def new_project_ref(domain_id=None, parent_id=None, is_domain=False, **kwargs):
def new_project_ref(domain_id=None, is_domain=False, **kwargs):
ref = {
'id': uuid.uuid4().hex,
'name': uuid.uuid4().hex,
'description': uuid.uuid4().hex,
'enabled': True,
'domain_id': domain_id,
'parent_id': parent_id,
'is_domain': is_domain,
}
# NOTE(henry-nash): We don't include parent_id in the initial list above
# since specifying it is optional depending on where the project sits in
# the hierarchy (and a parent_id of None has meaning - i.e. it's a top
# level project).
ref.update(kwargs)
return ref

View File

@ -2212,7 +2212,7 @@ class IdentityTests(AssignmentTestHelperMixin):
project = unit.new_project_ref(
name=unicode_project_name,
domain_id=CONF.identity.default_domain_id)
self.resource_api.create_project(project['id'], project)
project = self.resource_api.create_project(project['id'], project)
self.resource_api.update_project(project['id'], project)
self.resource_api.delete_project(project['id'])
@ -2474,7 +2474,7 @@ class IdentityTests(AssignmentTestHelperMixin):
def test_list_projects_with_multiple_filters(self):
# Create a project
project = unit.new_project_ref(domain_id=DEFAULT_DOMAIN_ID)
self.resource_api.create_project(project['id'], project)
project = self.resource_api.create_project(project['id'], project)
# Build driver hints with the project's name and inexistent description
hints = driver_hints.Hints()
@ -2548,7 +2548,7 @@ class IdentityTests(AssignmentTestHelperMixin):
project = unit.new_project_ref(domain_id=domain_id,
is_domain=is_domain)
project_id = project['id']
self.resource_api.create_project(project_id, project)
project = self.resource_api.create_project(project_id, project)
projects = [project]
for i in range(1, hierarchy_size):
@ -2665,18 +2665,11 @@ class IdentityTests(AssignmentTestHelperMixin):
@unit.skip_if_no_multiple_domains_support
def test_create_subproject_acting_as_domain_fails(self):
root_project = {'id': uuid.uuid4().hex,
'domain_id': DEFAULT_DOMAIN_ID,
'name': uuid.uuid4().hex,
'parent_id': None,
'is_domain': True}
root_project = unit.new_project_ref(is_domain=True)
self.resource_api.create_project(root_project['id'], root_project)
sub_project = {'id': uuid.uuid4().hex,
'domain_id': DEFAULT_DOMAIN_ID,
'name': uuid.uuid4().hex,
'parent_id': root_project['id'],
'is_domain': True}
sub_project = unit.new_project_ref(is_domain=True,
parent_id=root_project['id'])
# Creation of sub projects acting as domains is not allowed yet
self.assertRaises(exception.ValidationError,
@ -2719,8 +2712,7 @@ class IdentityTests(AssignmentTestHelperMixin):
@unit.skip_if_no_multiple_domains_support
def test_create_project_passing_is_domain_flag_true(self):
project = unit.new_project_ref(domain_id=DEFAULT_DOMAIN_ID,
is_domain=True)
project = unit.new_project_ref(is_domain=True)
ref = self.resource_api.create_project(project['id'], project)
self.assertTrue(ref['is_domain'])
@ -2732,11 +2724,12 @@ class IdentityTests(AssignmentTestHelperMixin):
ref = self.resource_api.create_project(project['id'], project)
self.assertIs(False, ref['is_domain'])
@test_utils.wip('waiting for projects acting as domains implementation')
@test_utils.wip('waiting for support for parent_id to imply domain_id')
def test_create_project_with_parent_id_and_without_domain_id(self):
project = unit.new_project_ref(domain_id=None)
# First create a domain
project = unit.new_project_ref(is_domain=True)
self.resource_api.create_project(project['id'], project)
# Now create a child by just naming the parent_id
sub_project = unit.new_project_ref(parent_id=project['id'])
ref = self.resource_api.create_project(sub_project['id'], sub_project)
@ -2745,9 +2738,10 @@ class IdentityTests(AssignmentTestHelperMixin):
@test_utils.wip('waiting for projects acting as domains implementation')
def test_create_project_with_domain_id_and_without_parent_id(self):
project = unit.new_project_ref(parent_id=None)
# First create a domain
project = unit.new_project_ref(is_domain=True)
self.resource_api.create_project(project['id'], project)
# Now create a child by just naming the domain_id
sub_project = unit.new_project_ref(domain_id=project['id'])
ref = self.resource_api.create_project(sub_project['id'], sub_project)
@ -2796,7 +2790,7 @@ class IdentityTests(AssignmentTestHelperMixin):
def test_list_projects_in_subtree_with_circular_reference(self):
project1 = unit.new_project_ref(domain_id=DEFAULT_DOMAIN_ID)
self.resource_api.create_project(project1['id'], project1)
project1 = self.resource_api.create_project(project1['id'], project1)
project2 = unit.new_project_ref(domain_id=DEFAULT_DOMAIN_ID,
parent_id=project1['id'])
@ -3674,7 +3668,7 @@ class IdentityTests(AssignmentTestHelperMixin):
# Creating a project with no description attribute.
project = unit.new_project_ref(domain_id=DEFAULT_DOMAIN_ID)
del project['description']
self.resource_api.create_project(project['id'], project)
project = self.resource_api.create_project(project['id'], project)
# Add a description attribute.
project['description'] = uuid.uuid4().hex
@ -3687,7 +3681,7 @@ class IdentityTests(AssignmentTestHelperMixin):
# Creating a project with no description attribute.
project = unit.new_project_ref(domain_id=DEFAULT_DOMAIN_ID)
del project['description']
self.resource_api.create_project(project['id'], project)
project = self.resource_api.create_project(project['id'], project)
# Add a description attribute.
project['description'] = ''
@ -3698,12 +3692,14 @@ class IdentityTests(AssignmentTestHelperMixin):
def test_domain_crud(self):
domain = unit.new_domain_ref()
self.resource_api.create_domain(domain['id'], domain)
domain_ref = self.resource_api.create_domain(domain['id'], domain)
self.assertDictEqual(domain, domain_ref)
domain_ref = self.resource_api.get_domain(domain['id'])
self.assertDictEqual(domain, domain_ref)
domain['name'] = uuid.uuid4().hex
self.resource_api.update_domain(domain['id'], domain)
domain_ref = self.resource_api.update_domain(domain['id'], domain)
self.assertDictEqual(domain, domain_ref)
domain_ref = self.resource_api.get_domain(domain['id'])
self.assertDictEqual(domain, domain_ref)
@ -6365,10 +6361,12 @@ class InheritanceTests(AssignmentTestHelperMixin):
# Enable OS-INHERIT extension
self.config_fixture.config(group='os_inherit', enabled=True)
root_project = unit.new_project_ref(domain_id=DEFAULT_DOMAIN_ID)
self.resource_api.create_project(root_project['id'], root_project)
root_project = self.resource_api.create_project(root_project['id'],
root_project)
leaf_project = unit.new_project_ref(domain_id=DEFAULT_DOMAIN_ID,
parent_id=root_project['id'])
self.resource_api.create_project(leaf_project['id'], leaf_project)
leaf_project = self.resource_api.create_project(leaf_project['id'],
leaf_project)
user = unit.new_user_ref(domain_id=DEFAULT_DOMAIN_ID)
user = self.identity_api.create_user(user)
@ -6557,10 +6555,12 @@ class InheritanceTests(AssignmentTestHelperMixin):
"""
self.config_fixture.config(group='os_inherit', enabled=True)
root_project = unit.new_project_ref(domain_id=DEFAULT_DOMAIN_ID)
self.resource_api.create_project(root_project['id'], root_project)
root_project = self.resource_api.create_project(root_project['id'],
root_project)
leaf_project = unit.new_project_ref(domain_id=DEFAULT_DOMAIN_ID,
parent_id=root_project['id'])
self.resource_api.create_project(leaf_project['id'], leaf_project)
leaf_project = self.resource_api.create_project(leaf_project['id'],
leaf_project)
user = unit.new_user_ref(domain_id=DEFAULT_DOMAIN_ID)
user = self.identity_api.create_user(user)

View File

@ -1477,7 +1477,7 @@ class LDAPIdentity(BaseLDAPIdentity, unit.TestCase):
project = unit.new_project_ref(
domain_id=CONF.identity.default_domain_id)
self.resource_api.create_project(project['id'], project)
project = self.resource_api.create_project(project['id'], project)
project_ref = self.resource_api.get_project(project['id'])
self.assertDictEqual(project, project_ref)
@ -1501,7 +1501,7 @@ class LDAPIdentity(BaseLDAPIdentity, unit.TestCase):
domain_id=CONF.identity.default_domain_id)
project_id = project['id']
# Create a project
self.resource_api.create_project(project_id, project)
project = self.resource_api.create_project(project_id, project)
self.resource_api.get_project(project_id)
updated_project = copy.deepcopy(project)
updated_project['description'] = uuid.uuid4().hex
@ -1548,7 +1548,7 @@ class LDAPIdentity(BaseLDAPIdentity, unit.TestCase):
def test_update_is_domain_field(self):
domain = self._get_domain_fixture()
project = unit.new_project_ref(domain_id=domain['id'])
self.resource_api.create_project(project['id'], project)
project = self.resource_api.create_project(project['id'], project)
# Try to update the is_domain field to True
project['is_domain'] = True
@ -1908,7 +1908,7 @@ class LDAPIdentityEnabledEmulation(LDAPIdentity):
project = unit.new_project_ref(
domain_id=CONF.identity.default_domain_id)
self.resource_api.create_project(project['id'], project)
project = self.resource_api.create_project(project['id'], project)
project_ref = self.resource_api.get_project(project['id'])
# self.resource_api.create_project adds an enabled
@ -2512,7 +2512,7 @@ class MultiLDAPandSQLIdentity(BaseLDAPIdentity, unit.SQLDriverOverrides,
domain = unit.new_domain_ref()
project = unit.new_project_ref(domain_id=domain['id'])
self.resource_api.create_domain(domain['id'], domain)
self.resource_api.create_project(project['id'], project)
project = self.resource_api.create_project(project['id'], project)
project_ref = self.resource_api.get_project(project['id'])
self.assertDictEqual(project, project_ref)

View File

@ -270,8 +270,8 @@ class SqlIdentity(SqlTests, test_backend.IdentityTests):
self.assertEqual(arbitrary_value, ref[arbitrary_key])
self.assertIsNone(ref.get('extra'))
project['name'] = uuid.uuid4().hex
ref = self.resource_api.update_project(project['id'], project)
ref['name'] = uuid.uuid4().hex
ref = self.resource_api.update_project(ref['id'], ref)
self.assertEqual(arbitrary_value, ref[arbitrary_key])
self.assertEqual(arbitrary_value, ref['extra'][arbitrary_key])

View File

@ -315,7 +315,8 @@ class RestfulTestCase(unit.SQLDriverOverrides, rest.RestfulTestCase,
self.project = unit.new_project_ref(domain_id=self.domain_id)
self.project_id = self.project['id']
self.resource_api.create_project(self.project_id, self.project)
self.project = self.resource_api.create_project(self.project_id,
self.project)
self.user = unit.create_user(self.identity_api,
domain_id=self.domain_id)

View File

@ -20,6 +20,7 @@ from keystone.common import controller
from keystone import exception
from keystone.tests import unit
from keystone.tests.unit import test_v3
from keystone.tests.unit import utils as test_utils
CONF = cfg.CONF
@ -92,6 +93,42 @@ class ResourceTestCase(test_v3.RestfulTestCase,
'/domains',
body={'domain': ref})
@test_utils.wip('waiting for projects acting as domains implementation')
def test_create_domain_creates_is_domain_project(self):
"""Call ``POST /domains`` and check a project that acts as a domain
is created.
"""
# Create a new domain
domain_ref = unit.new_domain_ref()
r = self.post('/domains', body={'domain': domain_ref})
self.assertValidDomainResponse(r, domain_ref)
# Retrieve its correspondent project
r = self.get('/projects/%(project_id)s' % {
'project_id': r.result['domain']['id']})
self.assertValidProjectResponse(r)
# The created project has is_domain flag as True
self.assertTrue(r.result['project']['is_domain'])
# And its parent_id and domain_id attributes are equal
self.assertIsNone(r.result['project']['parent_id'])
self.assertIsNone(r.result['project']['domain_id'])
@test_utils.wip('waiting for projects acting as domains implementation')
def test_create_is_domain_project_creates_domain(self):
"""Call ``POST /projects`` is_domain and check a domain is created."""
# Create a new project that acts as a domain
project_ref = unit.new_project_ref(domain_id=None, is_domain=True)
r = self.post('/projects', body={'project': project_ref})
self.assertValidProjectResponse(r)
# Retrieve its correspondent domain
r = self.get('/domains/%(domain_id)s' % {
'domain_id': r.result['project']['id']})
self.assertValidDomainResponse(r)
self.assertIsNotNone(r.result['domain'])
def test_list_domains(self):
"""Call ``GET /domains``."""
resource_url = '/domains'
@ -148,6 +185,28 @@ class ResourceTestCase(test_v3.RestfulTestCase,
'domain_id': self.domain_id},
body={'domain': ref})
@test_utils.wip('waiting for projects acting as domains implementation')
def test_update_domain_updates_is_domain_project(self):
"""Call ``PATCH /domains`` and check the project that acts as a domain
is updated.
"""
# Create a new domain
domain_ref = unit.new_domain_ref()
r = self.post('/domains', body={'domain': domain_ref})
self.assertValidDomainResponse(r, domain_ref)
# Disable it
self.patch('/domains/%s' % r.result['domain']['id'],
body={'domain': {'enabled': False}})
# Retrieve its correspondent project
r = self.get('/projects/%(project_id)s' % {
'project_id': r.result['domain']['id']})
self.assertValidProjectResponse(r)
# The created project is disabled as well
self.assertFalse(r.result['project']['enabled'])
def test_disable_domain(self):
"""Call ``PATCH /domains/{domain_id}`` (set enabled=False)."""
# Create a 2nd set of entities in a 2nd domain
@ -261,7 +320,7 @@ class ResourceTestCase(test_v3.RestfulTestCase,
self.resource_api.create_domain(domain2['id'], domain2)
project2 = unit.new_project_ref(domain_id=domain2['id'])
self.resource_api.create_project(project2['id'], project2)
project2 = self.resource_api.create_project(project2['id'], project2)
user2 = unit.new_user_ref(domain_id=domain2['id'],
project_id=project2['id'])
@ -313,6 +372,29 @@ class ResourceTestCase(test_v3.RestfulTestCase,
r = self.credential_api.get_credential(credential['id'])
self.assertDictEqual(credential, r)
@test_utils.wip('waiting for projects acting as domains implementation')
def test_delete_domain_deletes_is_domain_project(self):
"""Call ``DELETE /domains`` and check the project that acts as a domain
is deleted.
"""
# Create a new domain
domain_ref = unit.new_domain_ref()
r = self.post('/domains', body={'domain': domain_ref})
self.assertValidDomainResponse(r, domain_ref)
# Retrieve its correspondent project
self.get('/projects/%(project_id)s' % {
'project_id': r.result['domain']['id']})
# Delete the domain
self.patch('/domains/%s' % r.result['domain']['id'],
body={'domain': {'enabled': False}})
self.delete('/domains/%s' % r.result['domain']['id'])
# The created project is deleted as well
self.get('/projects/%(project_id)s' % {
'project_id': r.result['domain']['id']}, expected_status=404)
def test_delete_default_domain(self):
# Need to disable it first.
self.patch('/domains/%(domain_id)s' % {
@ -369,7 +451,8 @@ class ResourceTestCase(test_v3.RestfulTestCase,
self.resource_api.create_domain(domain['id'], domain)
root_project = unit.new_project_ref(domain_id=domain['id'])
self.resource_api.create_project(root_project['id'], root_project)
root_project = self.resource_api.create_project(root_project['id'],
root_project)
leaf_project = unit.new_project_ref(
domain_id=domain['id'],
@ -984,7 +1067,8 @@ class ResourceTestCase(test_v3.RestfulTestCase,
def test_update_project(self):
"""Call ``PATCH /projects/{project_id}``."""
ref = unit.new_project_ref(domain_id=self.domain_id)
ref = unit.new_project_ref(domain_id=self.domain_id,
parent_id=self.project['parent_id'])
del ref['id']
r = self.patch(
'/projects/%(project_id)s' % {
@ -999,7 +1083,8 @@ class ResourceTestCase(test_v3.RestfulTestCase,
self.config_fixture.config(group='resource',
project_name_url_safe='off')
ref = unit.new_project_ref(name=unsafe_name,
domain_id=self.domain_id)
domain_id=self.domain_id,
parent_id=self.project['parent_id'])
del ref['id']
self.patch(
'/projects/%(project_id)s' % {
@ -1011,7 +1096,8 @@ class ResourceTestCase(test_v3.RestfulTestCase,
self.config_fixture.config(group='resource',
project_name_url_safe=config_setting)
ref = unit.new_project_ref(name=unsafe_name,
domain_id=self.domain_id)
domain_id=self.domain_id,
parent_id=self.project['parent_id'])
del ref['id']
self.patch(
'/projects/%(project_id)s' % {
@ -1025,7 +1111,8 @@ class ResourceTestCase(test_v3.RestfulTestCase,
# By default, we should be able to create unsafe names
ref = unit.new_project_ref(name=unsafe_name,
domain_id=self.domain_id)
domain_id=self.domain_id,
parent_id=self.project['parent_id'])
del ref['id']
self.patch(
'/projects/%(project_id)s' % {
@ -1035,7 +1122,7 @@ class ResourceTestCase(test_v3.RestfulTestCase,
def test_update_project_domain_id(self):
"""Call ``PATCH /projects/{project_id}`` with domain_id."""
project = unit.new_project_ref(domain_id=self.domain['id'])
self.resource_api.create_project(project['id'], project)
project = self.resource_api.create_project(project['id'], project)
project['domain_id'] = CONF.identity.default_domain_id
r = self.patch('/projects/%(project_id)s' % {
'project_id': project['id']},
@ -1069,6 +1156,7 @@ class ResourceTestCase(test_v3.RestfulTestCase,
body={'project': project})
self.assertFalse(resp.result['project']['is_domain'])
project['parent_id'] = resp.result['project']['parent_id']
project['is_domain'] = True
self.patch('/projects/%(project_id)s' % {
'project_id': resp.result['project']['id']},