"Fossies" - the Fresh Open Source Software Archive  

Source code changes of the file "keystone/tests/unit/test_v3_resource.py" between
keystone-16.0.1.tar.gz and keystone-17.0.0.tar.gz

About: OpenStack Keystone (Core Service: Identity) provides an authentication and authorization service for other OpenStack services. Provides a catalog of endpoints for all OpenStack services.
The "Ussuri" series (latest release).

test_v3_resource.py  (keystone-16.0.1):test_v3_resource.py  (keystone-17.0.0)
skipping to change at line 15 skipping to change at line 15
# http://www.apache.org/licenses/LICENSE-2.0 # http://www.apache.org/licenses/LICENSE-2.0
# #
# Unless required by applicable law or agreed to in writing, software # Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT # distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the # WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
# License for the specific language governing permissions and limitations # License for the specific language governing permissions and limitations
# under the License. # under the License.
import uuid import uuid
from six.moves import http_client import http.client
from six.moves import range
from testtools import matchers from testtools import matchers
from keystone.common import provider_api from keystone.common import provider_api
import keystone.conf import keystone.conf
from keystone.credential.providers import fernet as credential_fernet from keystone.credential.providers import fernet as credential_fernet
from keystone import exception from keystone import exception
from keystone.tests import unit from keystone.tests import unit
from keystone.tests.unit import ksfixtures from keystone.tests.unit import ksfixtures
from keystone.tests.unit import test_v3 from keystone.tests.unit import test_v3
from keystone.tests.unit import utils as test_utils from keystone.tests.unit import utils as test_utils
skipping to change at line 76 skipping to change at line 75
# ensure the name is uppercase # ensure the name is uppercase
ref['name'] = ref['name'].upper() ref['name'] = ref['name'].upper()
r = self.post( r = self.post(
'/domains', '/domains',
body={'domain': ref}) body={'domain': ref})
self.assertValidDomainResponse(r, ref) self.assertValidDomainResponse(r, ref)
def test_create_domain_bad_request(self): def test_create_domain_bad_request(self):
"""Call ``POST /domains``.""" """Call ``POST /domains``."""
self.post('/domains', body={'domain': {}}, self.post('/domains', body={'domain': {}},
expected_status=http_client.BAD_REQUEST) expected_status=http.client.BAD_REQUEST)
def test_create_domain_unsafe(self): def test_create_domain_unsafe(self):
"""Call ``POST /domains with unsafe names``.""" """Call ``POST /domains with unsafe names``."""
unsafe_name = 'i am not / safe' unsafe_name = 'i am not / safe'
self.config_fixture.config(group='resource', self.config_fixture.config(group='resource',
domain_name_url_safe='off') domain_name_url_safe='off')
ref = unit.new_domain_ref(name=unsafe_name) ref = unit.new_domain_ref(name=unsafe_name)
self.post( self.post(
'/domains', '/domains',
body={'domain': ref}) body={'domain': ref})
for config_setting in ['new', 'strict']: for config_setting in ['new', 'strict']:
self.config_fixture.config(group='resource', self.config_fixture.config(group='resource',
domain_name_url_safe=config_setting) domain_name_url_safe=config_setting)
ref = unit.new_domain_ref(name=unsafe_name) ref = unit.new_domain_ref(name=unsafe_name)
self.post( self.post(
'/domains', '/domains',
body={'domain': ref}, body={'domain': ref},
expected_status=http_client.BAD_REQUEST) expected_status=http.client.BAD_REQUEST)
def test_create_domain_unsafe_default(self): def test_create_domain_unsafe_default(self):
"""Check default for unsafe names for ``POST /domains``.""" """Check default for unsafe names for ``POST /domains``."""
unsafe_name = 'i am not / safe' unsafe_name = 'i am not / safe'
# By default, we should be able to create unsafe names # By default, we should be able to create unsafe names
ref = unit.new_domain_ref(name=unsafe_name) ref = unit.new_domain_ref(name=unsafe_name)
self.post( self.post(
'/domains', '/domains',
body={'domain': ref}) body={'domain': ref})
skipping to change at line 174 skipping to change at line 173
ref['explicit_domain_id'] = explicit_domain_id ref['explicit_domain_id'] = explicit_domain_id
r = self.post( r = self.post(
'/domains', '/domains',
body={'domain': ref}) body={'domain': ref})
self.assertValidDomainResponse(r, ref) self.assertValidDomainResponse(r, ref)
# second one should fail # second one should fail
r = self.post( r = self.post(
'/domains', '/domains',
body={'domain': ref}, body={'domain': ref},
expected_status=http_client.CONFLICT) expected_status=http.client.CONFLICT)
def test_create_domain_invalid_explicit_ids(self): def test_create_domain_invalid_explicit_ids(self):
"""Call ``POST /domains`` with various invalid explicit_domain_ids.""" """Call ``POST /domains`` with various invalid explicit_domain_ids."""
ref = unit.new_domain_ref() ref = unit.new_domain_ref()
bad_ids = ['bad!', bad_ids = ['bad!',
'', '',
'9aea63518f0040c', '9aea63518f0040c',
'1234567890123456789012345678901234567890', '1234567890123456789012345678901234567890',
'9aea63518f0040c6b4518d8d2242911c9aea63518f0040c6b45'] '9aea63518f0040c6b4518d8d2242911c9aea63518f0040c6b45']
for explicit_domain_id in bad_ids: for explicit_domain_id in bad_ids:
ref['explicit_domain_id'] = explicit_domain_id ref['explicit_domain_id'] = explicit_domain_id
self.post('/domains', body={'domain': {}}, self.post('/domains', body={'domain': {}},
expected_status=http_client.BAD_REQUEST) expected_status=http.client.BAD_REQUEST)
def test_list_head_domains(self): def test_list_head_domains(self):
"""Call ``GET & HEAD /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) self.head(resource_url, expected_status=http.client.OK)
def test_list_limit_for_domains(self): def test_list_limit_for_domains(self):
for x in range(6): for x in range(6):
domain = {'domain': unit.new_domain_ref()} domain = {'domain': unit.new_domain_ref()}
self.post('/domains', body=domain) self.post('/domains', body=domain)
for expected_length in range(1, 6): for expected_length in range(1, 6):
self.config_fixture.config( self.config_fixture.config(
group='resource', list_limit=expected_length group='resource', list_limit=expected_length
) )
response = self.get('/domains') response = self.get('/domains')
domain_list = response.json_body['domains'] domain_list = response.json_body['domains']
self.assertEqual(expected_length, len(domain_list)) self.assertEqual(expected_length, len(domain_list))
def test_get_head_domain(self): def test_get_head_domain(self):
"""Call ``GET /domains/{domain_id}``.""" """Call ``GET /domains/{domain_id}``."""
resource_url = '/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) r = self.get(resource_url)
self.assertValidDomainResponse(r, self.domain) self.assertValidDomainResponse(r, self.domain)
self.head(resource_url, expected_status=http_client.OK) 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}``."""
ref = unit.new_domain_ref() ref = unit.new_domain_ref()
del ref['id'] del ref['id']
r = self.patch('/domains/%(domain_id)s' % { r = self.patch('/domains/%(domain_id)s' % {
'domain_id': self.domain_id}, 'domain_id': self.domain_id},
body={'domain': ref}) body={'domain': ref})
self.assertValidDomainResponse(r, ref) self.assertValidDomainResponse(r, ref)
skipping to change at line 250 skipping to change at line 249
unsafe_name = 'i am still not / safe' unsafe_name = 'i am still not / safe'
for config_setting in ['new', 'strict']: for config_setting in ['new', 'strict']:
self.config_fixture.config(group='resource', self.config_fixture.config(group='resource',
domain_name_url_safe=config_setting) domain_name_url_safe=config_setting)
ref = unit.new_domain_ref(name=unsafe_name) ref = unit.new_domain_ref(name=unsafe_name)
del ref['id'] del ref['id']
self.patch('/domains/%(domain_id)s' % { self.patch('/domains/%(domain_id)s' % {
'domain_id': self.domain_id}, 'domain_id': self.domain_id},
body={'domain': ref}, body={'domain': ref},
expected_status=http_client.BAD_REQUEST) expected_status=http.client.BAD_REQUEST)
def test_update_domain_unsafe_default(self): def test_update_domain_unsafe_default(self):
"""Check default for unsafe names for ``POST /domains``.""" """Check default for unsafe names for ``POST /domains``."""
unsafe_name = 'i am not / safe' unsafe_name = 'i am not / safe'
# By default, we should be able to create unsafe names # By default, we should be able to create unsafe names
ref = unit.new_domain_ref(name=unsafe_name) ref = unit.new_domain_ref(name=unsafe_name)
del ref['id'] del ref['id']
self.patch('/domains/%(domain_id)s' % { self.patch('/domains/%(domain_id)s' % {
'domain_id': self.domain_id}, 'domain_id': self.domain_id},
skipping to change at line 325 skipping to change at line 324
'domain_id': domain2['id']}, 'domain_id': domain2['id']},
body={'domain': {'enabled': False}}) body={'domain': {'enabled': False}})
self.assertValidDomainResponse(r, domain2) self.assertValidDomainResponse(r, domain2)
# Try looking up in v3 by name and id # Try looking up in v3 by name and id
auth_data = self.build_authentication_request( auth_data = self.build_authentication_request(
user_id=user2['id'], user_id=user2['id'],
password=user2['password'], password=user2['password'],
project_id=project2['id']) project_id=project2['id'])
self.v3_create_token(auth_data, self.v3_create_token(auth_data,
expected_status=http_client.UNAUTHORIZED) expected_status=http.client.UNAUTHORIZED)
auth_data = self.build_authentication_request( auth_data = self.build_authentication_request(
username=user2['name'], username=user2['name'],
user_domain_id=domain2['id'], user_domain_id=domain2['id'],
password=user2['password'], password=user2['password'],
project_id=project2['id']) project_id=project2['id'])
self.v3_create_token(auth_data, self.v3_create_token(auth_data,
expected_status=http_client.UNAUTHORIZED) expected_status=http.client.UNAUTHORIZED)
def test_delete_enabled_domain_fails(self): def test_delete_enabled_domain_fails(self):
"""Call ``DELETE /domains/{domain_id}`` (when domain enabled).""" """Call ``DELETE /domains/{domain_id}`` (when domain enabled)."""
# Try deleting an enabled domain, which should fail # Try deleting an enabled domain, which should fail
self.delete('/domains/%(domain_id)s' % { self.delete('/domains/%(domain_id)s' % {
'domain_id': self.domain['id']}, 'domain_id': self.domain['id']},
expected_status=exception.ForbiddenAction.code) expected_status=exception.ForbiddenAction.code)
def test_delete_domain(self): def test_delete_domain(self):
"""Call ``DELETE /domains/{domain_id}``. """Call ``DELETE /domains/{domain_id}``.
skipping to change at line 442 skipping to change at line 441
def test_delete_domain_with_idp(self): def test_delete_domain_with_idp(self):
# Create a new domain # Create a new domain
domain_ref = unit.new_domain_ref() domain_ref = unit.new_domain_ref()
r = self.post('/domains', body={'domain': domain_ref}) r = self.post('/domains', body={'domain': domain_ref})
self.assertValidDomainResponse(r, domain_ref) self.assertValidDomainResponse(r, domain_ref)
domain_id = r.result['domain']['id'] domain_id = r.result['domain']['id']
# Create a Idp in the domain # Create a Idp in the domain
self.put('/OS-FEDERATION/identity_providers/test_idp', self.put('/OS-FEDERATION/identity_providers/test_idp',
body={"identity_provider": { body={"identity_provider": {
"domain_id": domain_id}}, "domain_id": domain_id}},
expected_status=http_client.CREATED) expected_status=http.client.CREATED)
# Disable and delete the domain with no error. # Disable and delete the domain with no error.
self.patch('/domains/%(domain_id)s' % { self.patch('/domains/%(domain_id)s' % {
'domain_id': domain_id}, 'domain_id': domain_id},
body={'domain': {'enabled': False}}) body={'domain': {'enabled': False}})
self.delete('/domains/%s' % domain_id) self.delete('/domains/%s' % domain_id)
# The Idp is deleted as well # The Idp is deleted as well
self.get('/OS-FEDERATION/identity_providers/test_idp', self.get('/OS-FEDERATION/identity_providers/test_idp',
expected_status=http_client.NOT_FOUND) expected_status=http.client.NOT_FOUND)
def test_delete_domain_deletes_is_domain_project(self): def test_delete_domain_deletes_is_domain_project(self):
"""Check the project that acts as a domain is deleted. """Check the project that acts as a domain is deleted.
Call ``DELETE /domains``. Call ``DELETE /domains``.
""" """
# Create a new domain # Create a new domain
domain_ref = unit.new_domain_ref() domain_ref = unit.new_domain_ref()
r = self.post('/domains', body={'domain': domain_ref}) r = self.post('/domains', body={'domain': domain_ref})
self.assertValidDomainResponse(r, domain_ref) self.assertValidDomainResponse(r, domain_ref)
skipping to change at line 511 skipping to change at line 510
password=user2['password']) password=user2['password'])
# sends a request for the user's token # sends a request for the user's token
token_resp = self.post('/auth/tokens', body=auth_body) token_resp = self.post('/auth/tokens', body=auth_body)
subject_token = token_resp.headers.get('x-subject-token') subject_token = token_resp.headers.get('x-subject-token')
# validates the returned token and it should be valid. # validates the returned token and it should be valid.
self.head('/auth/tokens', self.head('/auth/tokens',
headers={'x-subject-token': subject_token}, headers={'x-subject-token': subject_token},
expected_status=http_client.OK) expected_status=http.client.OK)
# now disable the domain # now disable the domain
domain['enabled'] = False domain['enabled'] = False
url = "/domains/%(domain_id)s" % {'domain_id': domain['id']} url = "/domains/%(domain_id)s" % {'domain_id': domain['id']}
self.patch(url, self.patch(url,
body={'domain': {'enabled': False}}) body={'domain': {'enabled': False}})
# validates the same token again and it should be 'not found' # validates the same token again and it should be 'not found'
# as the domain has already been disabled. # as the domain has already been disabled.
self.head('/auth/tokens', self.head('/auth/tokens',
headers={'x-subject-token': subject_token}, headers={'x-subject-token': subject_token},
expected_status=http_client.NOT_FOUND) expected_status=http.client.NOT_FOUND)
def test_delete_domain_hierarchy(self): def test_delete_domain_hierarchy(self):
"""Call ``DELETE /domains/{domain_id}``.""" """Call ``DELETE /domains/{domain_id}``."""
domain = unit.new_domain_ref() domain = unit.new_domain_ref()
PROVIDERS.resource_api.create_domain(domain['id'], domain) PROVIDERS.resource_api.create_domain(domain['id'], domain)
root_project = unit.new_project_ref(domain_id=domain['id']) root_project = unit.new_project_ref(domain_id=domain['id'])
root_project = PROVIDERS.resource_api.create_project( root_project = PROVIDERS.resource_api.create_project(
root_project['id'], root_project root_project['id'], root_project
) )
skipping to change at line 628 skipping to change at line 627
domain['id'], domain) domain['id'], domain)
# Project CRUD tests # Project CRUD tests
def test_list_head_projects(self): def test_list_head_projects(self):
"""Call ``GET & HEAD /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) 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``."""
ref = unit.new_project_ref(domain_id=self.domain_id) ref = unit.new_project_ref(domain_id=self.domain_id)
r = self.post( r = self.post(
'/projects', '/projects',
body={'project': ref}) body={'project': ref})
self.assertValidProjectResponse(r, ref) self.assertValidProjectResponse(r, ref)
def test_create_project_bad_request(self): def test_create_project_bad_request(self):
"""Call ``POST /projects``.""" """Call ``POST /projects``."""
self.post('/projects', body={'project': {}}, self.post('/projects', body={'project': {}},
expected_status=http_client.BAD_REQUEST) expected_status=http.client.BAD_REQUEST)
def test_create_project_invalid_domain_id(self): def test_create_project_invalid_domain_id(self):
"""Call ``POST /projects``.""" """Call ``POST /projects``."""
ref = unit.new_project_ref(domain_id=uuid.uuid4().hex) ref = unit.new_project_ref(domain_id=uuid.uuid4().hex)
self.post('/projects', body={'project': ref}, self.post('/projects', body={'project': ref},
expected_status=http_client.BAD_REQUEST) expected_status=http.client.BAD_REQUEST)
def test_create_project_unsafe(self): def test_create_project_unsafe(self):
"""Call ``POST /projects with unsafe names``.""" """Call ``POST /projects with unsafe names``."""
unsafe_name = 'i am not / safe' unsafe_name = 'i am not / safe'
self.config_fixture.config(group='resource', self.config_fixture.config(group='resource',
project_name_url_safe='off') project_name_url_safe='off')
ref = unit.new_project_ref(name=unsafe_name) ref = unit.new_project_ref(name=unsafe_name)
self.post( self.post(
'/projects', '/projects',
body={'project': ref}) body={'project': ref})
for config_setting in ['new', 'strict']: for config_setting in ['new', 'strict']:
self.config_fixture.config(group='resource', self.config_fixture.config(group='resource',
project_name_url_safe=config_setting) project_name_url_safe=config_setting)
ref = unit.new_project_ref(name=unsafe_name) ref = unit.new_project_ref(name=unsafe_name)
self.post( self.post(
'/projects', '/projects',
body={'project': ref}, body={'project': ref},
expected_status=http_client.BAD_REQUEST) expected_status=http.client.BAD_REQUEST)
def test_create_project_unsafe_default(self): def test_create_project_unsafe_default(self):
"""Check default for unsafe names for ``POST /projects``.""" """Check default for unsafe names for ``POST /projects``."""
unsafe_name = 'i am not / safe' unsafe_name = 'i am not / safe'
# By default, we should be able to create unsafe names # By default, we should be able to create unsafe names
ref = unit.new_project_ref(name=unsafe_name) ref = unit.new_project_ref(name=unsafe_name)
self.post( self.post(
'/projects', '/projects',
body={'project': ref}) body={'project': ref})
skipping to change at line 988 skipping to change at line 987
def test_create_hierarchical_project(self): def test_create_hierarchical_project(self):
"""Call ``POST /projects``.""" """Call ``POST /projects``."""
self._create_projects_hierarchy() self._create_projects_hierarchy()
def test_get_head_project(self): def test_get_head_project(self):
"""Call ``GET & HEAD /projects/{project_id}``.""" """Call ``GET & HEAD /projects/{project_id}``."""
resource_url = '/projects/%(project_id)s' % { resource_url = '/projects/%(project_id)s' % {
'project_id': self.project_id} 'project_id': self.project_id}
r = self.get(resource_url) r = self.get(resource_url)
self.assertValidProjectResponse(r, self.project) self.assertValidProjectResponse(r, self.project)
self.head(resource_url, expected_status=http_client.OK) 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``."""
self.get('/projects/%(project_id)s?parents_as_list' % { self.get('/projects/%(project_id)s?parents_as_list' % {
'project_id': None}, expected_status=http_client.NOT_FOUND) 'project_id': None}, expected_status=http.client.NOT_FOUND)
self.get('/projects/%(project_id)s?parents_as_list' % { self.get('/projects/%(project_id)s?parents_as_list' % {
'project_id': uuid.uuid4().hex}, 'project_id': uuid.uuid4().hex},
expected_status=http_client.NOT_FOUND) expected_status=http.client.NOT_FOUND)
def test_get_project_with_subtree_as_list_with_invalid_id(self): def test_get_project_with_subtree_as_list_with_invalid_id(self):
"""Call ``GET /projects/{project_id}?subtree_as_list``.""" """Call ``GET /projects/{project_id}?subtree_as_list``."""
self.get('/projects/%(project_id)s?subtree_as_list' % { self.get('/projects/%(project_id)s?subtree_as_list' % {
'project_id': None}, expected_status=http_client.NOT_FOUND) 'project_id': None}, expected_status=http.client.NOT_FOUND)
self.get('/projects/%(project_id)s?subtree_as_list' % { self.get('/projects/%(project_id)s?subtree_as_list' % {
'project_id': uuid.uuid4().hex}, 'project_id': uuid.uuid4().hex},
expected_status=http_client.NOT_FOUND) expected_status=http.client.NOT_FOUND)
def test_get_project_with_parents_as_ids(self): def test_get_project_with_parents_as_ids(self):
"""Call ``GET /projects/{project_id}?parents_as_ids``.""" """Call ``GET /projects/{project_id}?parents_as_ids``."""
projects = self._create_projects_hierarchy(hierarchy_size=2) projects = self._create_projects_hierarchy(hierarchy_size=2)
# Query for projects[2] parents_as_ids # Query for projects[2] parents_as_ids
r = self.get( r = self.get(
'/projects/%(project_id)s?parents_as_ids' % { '/projects/%(project_id)s?parents_as_ids' % {
'project_id': projects[2]['project']['id']}) 'project_id': projects[2]['project']['id']})
skipping to change at line 1137 skipping to change at line 1136
This uses ``GET /projects/{project_id}?parents_as_list&parents_as_ids`` This uses ``GET /projects/{project_id}?parents_as_list&parents_as_ids``
which should fail with a Bad Request due to the conflicting query which should fail with a Bad Request due to the conflicting query
strings. strings.
""" """
projects = self._create_projects_hierarchy(hierarchy_size=2) projects = self._create_projects_hierarchy(hierarchy_size=2)
self.get( self.get(
'/projects/%(project_id)s?parents_as_list&parents_as_ids' % { '/projects/%(project_id)s?parents_as_list&parents_as_ids' % {
'project_id': projects[1]['project']['id']}, 'project_id': projects[1]['project']['id']},
expected_status=http_client.BAD_REQUEST) expected_status=http.client.BAD_REQUEST)
def test_get_project_with_include_limits(self): def test_get_project_with_include_limits(self):
PROVIDERS.assignment_api.create_system_grant_for_user( PROVIDERS.assignment_api.create_system_grant_for_user(
self.user_id, self.role_id self.user_id, self.role_id
) )
system_admin_token = self.get_system_scoped_token() system_admin_token = self.get_system_scoped_token()
parent, project, subproject = self._create_projects_hierarchy(2) parent, project, subproject = self._create_projects_hierarchy(2)
# Assign a role for the user on all the created projects # Assign a role for the user on all the created projects
for proj in (parent, project, subproject): for proj in (parent, project, subproject):
skipping to change at line 1159 skipping to change at line 1158
role_id=self.role_id, user_id=self.user_id, role_id=self.role_id, user_id=self.user_id,
project_id=proj['project']['id'])) project_id=proj['project']['id']))
# create a registered limit and three limits for each project. # create a registered limit and three limits for each project.
reg_limit = unit.new_registered_limit_ref(service_id=self.service_id, reg_limit = unit.new_registered_limit_ref(service_id=self.service_id,
region_id=self.region_id, region_id=self.region_id,
resource_name='volume') resource_name='volume')
self.post( self.post(
'/registered_limits', '/registered_limits',
body={'registered_limits': [reg_limit]}, body={'registered_limits': [reg_limit]},
token=system_admin_token, token=system_admin_token,
expected_status=http_client.CREATED) expected_status=http.client.CREATED)
limit1 = unit.new_limit_ref(project_id=parent['project']['id'], limit1 = unit.new_limit_ref(project_id=parent['project']['id'],
service_id=self.service_id, service_id=self.service_id,
region_id=self.region_id, region_id=self.region_id,
resource_name='volume') resource_name='volume')
limit2 = unit.new_limit_ref(project_id=project['project']['id'], limit2 = unit.new_limit_ref(project_id=project['project']['id'],
service_id=self.service_id, service_id=self.service_id,
region_id=self.region_id, region_id=self.region_id,
resource_name='volume') resource_name='volume')
limit3 = unit.new_limit_ref(project_id=subproject['project']['id'], limit3 = unit.new_limit_ref(project_id=subproject['project']['id'],
service_id=self.service_id, service_id=self.service_id,
region_id=self.region_id, region_id=self.region_id,
resource_name='volume') resource_name='volume')
self.post( self.post(
'/limits', '/limits',
body={'limits': [limit1, limit2, limit3]}, body={'limits': [limit1, limit2, limit3]},
token=system_admin_token, token=system_admin_token,
expected_status=http_client.CREATED) expected_status=http.client.CREATED)
# "include_limits" should work together with "parents_as_list" or # "include_limits" should work together with "parents_as_list" or
# "subtree_as_list". Only using "include_limits" really does nothing. # "subtree_as_list". Only using "include_limits" really does nothing.
r = self.get('/projects/%(project_id)s?include_limits' % r = self.get('/projects/%(project_id)s?include_limits' %
{'project_id': subproject['project']['id']}) {'project_id': subproject['project']['id']})
self.assertNotIn('parents', r.result['project']) self.assertNotIn('parents', r.result['project'])
self.assertNotIn('subtree', r.result['project']) self.assertNotIn('subtree', r.result['project'])
self.assertNotIn('limits', r.result['project']) self.assertNotIn('limits', r.result['project'])
# using "include_limits" with "parents_as_list" # using "include_limits" with "parents_as_list"
skipping to change at line 1431 skipping to change at line 1430
This uses ``GET /projects/{project_id}?subtree_as_list&subtree_as_ids`` This uses ``GET /projects/{project_id}?subtree_as_list&subtree_as_ids``
which should fail with a bad request due to the conflicting query which should fail with a bad request due to the conflicting query
strings. strings.
""" """
projects = self._create_projects_hierarchy(hierarchy_size=2) projects = self._create_projects_hierarchy(hierarchy_size=2)
self.get( self.get(
'/projects/%(project_id)s?subtree_as_list&subtree_as_ids' % { '/projects/%(project_id)s?subtree_as_list&subtree_as_ids' % {
'project_id': projects[1]['project']['id']}, 'project_id': projects[1]['project']['id']},
expected_status=http_client.BAD_REQUEST) expected_status=http.client.BAD_REQUEST)
def test_update_project(self): def test_update_project(self):
"""Call ``PATCH /projects/{project_id}``.""" """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']) parent_id=self.project['parent_id'])
del ref['id'] del ref['id']
r = self.patch( r = self.patch(
'/projects/%(project_id)s' % { '/projects/%(project_id)s' % {
'project_id': self.project_id}, 'project_id': self.project_id},
body={'project': ref}) body={'project': ref})
skipping to change at line 1471 skipping to change at line 1470
self.config_fixture.config(group='resource', self.config_fixture.config(group='resource',
project_name_url_safe=config_setting) project_name_url_safe=config_setting)
ref = unit.new_project_ref(name=unsafe_name, ref = unit.new_project_ref(name=unsafe_name,
domain_id=self.domain_id, domain_id=self.domain_id,
parent_id=self.project['parent_id']) parent_id=self.project['parent_id'])
del ref['id'] del ref['id']
self.patch( self.patch(
'/projects/%(project_id)s' % { '/projects/%(project_id)s' % {
'project_id': self.project_id}, 'project_id': self.project_id},
body={'project': ref}, body={'project': ref},
expected_status=http_client.BAD_REQUEST) expected_status=http.client.BAD_REQUEST)
def test_update_project_unsafe_default(self): def test_update_project_unsafe_default(self):
"""Check default for unsafe names for ``POST /projects``.""" """Check default for unsafe names for ``POST /projects``."""
unsafe_name = 'i am not / safe' unsafe_name = 'i am not / safe'
# By default, we should be able to create unsafe names # By default, we should be able to create unsafe names
ref = unit.new_project_ref(name=unsafe_name, ref = unit.new_project_ref(name=unsafe_name,
domain_id=self.domain_id, domain_id=self.domain_id,
parent_id=self.project['parent_id']) parent_id=self.project['parent_id'])
del ref['id'] del ref['id']
skipping to change at line 1510 skipping to change at line 1509
def test_update_project_parent_id(self): def test_update_project_parent_id(self):
"""Call ``PATCH /projects/{project_id}``.""" """Call ``PATCH /projects/{project_id}``."""
projects = self._create_projects_hierarchy() projects = self._create_projects_hierarchy()
leaf_project = projects[1]['project'] leaf_project = projects[1]['project']
leaf_project['parent_id'] = None leaf_project['parent_id'] = None
self.patch( self.patch(
'/projects/%(project_id)s' % { '/projects/%(project_id)s' % {
'project_id': leaf_project['id']}, 'project_id': leaf_project['id']},
body={'project': leaf_project}, body={'project': leaf_project},
expected_status=http_client.FORBIDDEN) expected_status=http.client.FORBIDDEN)
def test_update_project_is_domain_not_allowed(self): def test_update_project_is_domain_not_allowed(self):
"""Call ``PATCH /projects/{project_id}`` with is_domain. """Call ``PATCH /projects/{project_id}`` with is_domain.
The is_domain flag is immutable. The is_domain flag is immutable.
""" """
project = unit.new_project_ref(domain_id=self.domain['id']) project = unit.new_project_ref(domain_id=self.domain['id'])
resp = self.post('/projects', resp = self.post('/projects',
body={'project': project}) body={'project': project})
self.assertFalse(resp.result['project']['is_domain']) self.assertFalse(resp.result['project']['is_domain'])
project['parent_id'] = resp.result['project']['parent_id'] project['parent_id'] = resp.result['project']['parent_id']
project['is_domain'] = True project['is_domain'] = True
self.patch('/projects/%(project_id)s' % { self.patch('/projects/%(project_id)s' % {
'project_id': resp.result['project']['id']}, 'project_id': resp.result['project']['id']},
body={'project': project}, body={'project': project},
expected_status=http_client.BAD_REQUEST) expected_status=http.client.BAD_REQUEST)
def test_disable_leaf_project(self): def test_disable_leaf_project(self):
"""Call ``PATCH /projects/{project_id}``.""" """Call ``PATCH /projects/{project_id}``."""
projects = self._create_projects_hierarchy() projects = self._create_projects_hierarchy()
leaf_project = projects[1]['project'] leaf_project = projects[1]['project']
leaf_project['enabled'] = False leaf_project['enabled'] = False
r = self.patch( r = self.patch(
'/projects/%(project_id)s' % { '/projects/%(project_id)s' % {
'project_id': leaf_project['id']}, 'project_id': leaf_project['id']},
body={'project': leaf_project}) body={'project': leaf_project})
skipping to change at line 1550 skipping to change at line 1549
def test_disable_not_leaf_project(self): def test_disable_not_leaf_project(self):
"""Call ``PATCH /projects/{project_id}``.""" """Call ``PATCH /projects/{project_id}``."""
projects = self._create_projects_hierarchy() projects = self._create_projects_hierarchy()
root_project = projects[0]['project'] root_project = projects[0]['project']
root_project['enabled'] = False root_project['enabled'] = False
self.patch( self.patch(
'/projects/%(project_id)s' % { '/projects/%(project_id)s' % {
'project_id': root_project['id']}, 'project_id': root_project['id']},
body={'project': root_project}, body={'project': root_project},
expected_status=http_client.FORBIDDEN) expected_status=http.client.FORBIDDEN)
def test_delete_project(self): def test_delete_project(self):
"""Call ``DELETE /projects/{project_id}``. """Call ``DELETE /projects/{project_id}``.
As well as making sure the delete succeeds, we ensure As well as making sure the delete succeeds, we ensure
that any credentials that reference this projects are that any credentials that reference this projects are
also deleted, while other credentials are unaffected. also deleted, while other credentials are unaffected.
""" """
credential = unit.new_credential_ref(user_id=self.user['id'], credential = unit.new_credential_ref(user_id=self.user['id'],
skipping to change at line 1598 skipping to change at line 1597
# But the credential for project2 is unaffected # But the credential for project2 is unaffected
r = PROVIDERS.credential_api.get_credential(credential2['id']) r = PROVIDERS.credential_api.get_credential(credential2['id'])
self.assertDictEqual(credential2, r) self.assertDictEqual(credential2, r)
def test_delete_not_leaf_project(self): def test_delete_not_leaf_project(self):
"""Call ``DELETE /projects/{project_id}``.""" """Call ``DELETE /projects/{project_id}``."""
projects = self._create_projects_hierarchy() projects = self._create_projects_hierarchy()
self.delete( self.delete(
'/projects/%(project_id)s' % { '/projects/%(project_id)s' % {
'project_id': projects[0]['project']['id']}, 'project_id': projects[0]['project']['id']},
expected_status=http_client.FORBIDDEN) expected_status=http.client.FORBIDDEN)
def test_create_project_with_tags(self): def test_create_project_with_tags(self):
project, tags = self._create_project_and_tags(num_of_tags=10) project, tags = self._create_project_and_tags(num_of_tags=10)
ref = self.get( ref = self.get(
'/projects/%(project_id)s' % { '/projects/%(project_id)s' % {
'project_id': project['id']}, 'project_id': project['id']},
expected_status=http_client.OK) expected_status=http.client.OK)
self.assertIn('tags', ref.result['project']) self.assertIn('tags', ref.result['project'])
for tag in tags: for tag in tags:
self.assertIn(tag, ref.result['project']['tags']) self.assertIn(tag, ref.result['project']['tags'])
def test_update_project_with_tags(self): def test_update_project_with_tags(self):
project, tags = self._create_project_and_tags(num_of_tags=9) project, tags = self._create_project_and_tags(num_of_tags=9)
tag = uuid.uuid4().hex tag = uuid.uuid4().hex
project['tags'].append(tag) project['tags'].append(tag)
ref = self.patch( ref = self.patch(
'/projects/%(project_id)s' % { '/projects/%(project_id)s' % {
'project_id': self.project_id}, 'project_id': self.project_id},
body={'project': {'tags': project['tags']}}) body={'project': {'tags': project['tags']}})
self.assertIn(tag, ref.result['project']['tags']) self.assertIn(tag, ref.result['project']['tags'])
def test_create_project_tag(self): def test_create_project_tag(self):
tag = uuid.uuid4().hex tag = uuid.uuid4().hex
url = '/projects/%(project_id)s/tags/%(value)s' url = '/projects/%(project_id)s/tags/%(value)s'
self.put(url % {'project_id': self.project_id, 'value': tag}, self.put(url % {'project_id': self.project_id, 'value': tag},
expected_status=http_client.CREATED) expected_status=http.client.CREATED)
self.get(url % {'project_id': self.project_id, 'value': tag}, self.get(url % {'project_id': self.project_id, 'value': tag},
expected_status=http_client.NO_CONTENT) expected_status=http.client.NO_CONTENT)
def test_create_project_tag_is_case_insensitive(self): def test_create_project_tag_is_case_insensitive(self):
case_tags = ['case', 'CASE'] case_tags = ['case', 'CASE']
for tag in case_tags: for tag in case_tags:
self.put( self.put(
'/projects/%(project_id)s/tags/%(value)s' % { '/projects/%(project_id)s/tags/%(value)s' % {
'project_id': self.project_id, 'project_id': self.project_id,
'value': tag}, 'value': tag},
expected_status=http_client.CREATED) expected_status=http.client.CREATED)
resp = self.get('/projects/%(project_id)s' % resp = self.get('/projects/%(project_id)s' %
{'project_id': self.project_id}, {'project_id': self.project_id},
expected_status=http_client.OK) expected_status=http.client.OK)
for tag in case_tags: for tag in case_tags:
self.assertIn(tag, resp.result['project']['tags']) self.assertIn(tag, resp.result['project']['tags'])
def test_get_single_project_tag(self): def test_get_single_project_tag(self):
project, tags = self._create_project_and_tags() project, tags = self._create_project_and_tags()
self.get( self.get(
'/projects/%(project_id)s/tags/%(value)s' % { '/projects/%(project_id)s/tags/%(value)s' % {
'project_id': project['id'], 'project_id': project['id'],
'value': tags[0]}, 'value': tags[0]},
expected_status=http_client.NO_CONTENT) expected_status=http.client.NO_CONTENT)
self.head( self.head(
'/projects/%(project_id)s/tags/%(value)s' % { '/projects/%(project_id)s/tags/%(value)s' % {
'project_id': project['id'], 'project_id': project['id'],
'value': tags[0]}, 'value': tags[0]},
expected_status=http_client.NO_CONTENT) expected_status=http.client.NO_CONTENT)
def test_get_project_tag_that_does_not_exist(self): def test_get_project_tag_that_does_not_exist(self):
project, _ = self._create_project_and_tags() project, _ = self._create_project_and_tags()
self.get( self.get(
'/projects/%(project_id)s/tags/%(value)s' % { '/projects/%(project_id)s/tags/%(value)s' % {
'project_id': project['id'], 'project_id': project['id'],
'value': uuid.uuid4().hex}, 'value': uuid.uuid4().hex},
expected_status=http_client.NOT_FOUND) expected_status=http.client.NOT_FOUND)
def test_delete_project_tag(self): def test_delete_project_tag(self):
project, tags = self._create_project_and_tags() project, tags = self._create_project_and_tags()
self.delete( self.delete(
'/projects/%(project_id)s/tags/%(value)s' % { '/projects/%(project_id)s/tags/%(value)s' % {
'project_id': project['id'], 'project_id': project['id'],
'value': tags[0]}, 'value': tags[0]},
expected_status=http_client.NO_CONTENT) expected_status=http.client.NO_CONTENT)
self.get( self.get(
'/projects/%(project_id)s/tags/%(value)s' % { '/projects/%(project_id)s/tags/%(value)s' % {
'project_id': self.project_id, 'project_id': self.project_id,
'value': tags[0]}, 'value': tags[0]},
expected_status=http_client.NOT_FOUND) expected_status=http.client.NOT_FOUND)
def test_delete_project_tags(self): def test_delete_project_tags(self):
project, tags = self._create_project_and_tags(num_of_tags=5) project, tags = self._create_project_and_tags(num_of_tags=5)
self.delete( self.delete(
'/projects/%(project_id)s/tags/' % { '/projects/%(project_id)s/tags/' % {
'project_id': project['id']}, 'project_id': project['id']},
expected_status=http_client.NO_CONTENT) expected_status=http.client.NO_CONTENT)
self.get( self.get(
'/projects/%(project_id)s/tags/%(value)s' % { '/projects/%(project_id)s/tags/%(value)s' % {
'project_id': self.project_id, 'project_id': self.project_id,
'value': tags[0]}, 'value': tags[0]},
expected_status=http_client.NOT_FOUND) expected_status=http.client.NOT_FOUND)
resp = self.get( resp = self.get(
'/projects/%(project_id)s/tags/' % { '/projects/%(project_id)s/tags/' % {
'project_id': self.project_id}, 'project_id': self.project_id},
expected_status=http_client.OK) expected_status=http.client.OK)
self.assertEqual(len(resp.result['tags']), 0) self.assertEqual(len(resp.result['tags']), 0)
def test_create_project_tag_invalid_project_id(self): def test_create_project_tag_invalid_project_id(self):
self.put( self.put(
'/projects/%(project_id)s/tags/%(value)s' % { '/projects/%(project_id)s/tags/%(value)s' % {
'project_id': uuid.uuid4().hex, 'project_id': uuid.uuid4().hex,
'value': uuid.uuid4().hex}, 'value': uuid.uuid4().hex},
expected_status=http_client.NOT_FOUND) expected_status=http.client.NOT_FOUND)
def test_create_project_tag_unsafe_name(self): def test_create_project_tag_unsafe_name(self):
tag = uuid.uuid4().hex + ',' tag = uuid.uuid4().hex + ','
self.put( self.put(
'/projects/%(project_id)s/tags/%(value)s' % { '/projects/%(project_id)s/tags/%(value)s' % {
'project_id': self.project_id, 'project_id': self.project_id,
'value': tag}, 'value': tag},
expected_status=http_client.BAD_REQUEST) expected_status=http.client.BAD_REQUEST)
def test_create_project_tag_already_exists(self): def test_create_project_tag_already_exists(self):
project, tags = self._create_project_and_tags() project, tags = self._create_project_and_tags()
self.put( self.put(
'/projects/%(project_id)s/tags/%(value)s' % { '/projects/%(project_id)s/tags/%(value)s' % {
'project_id': project['id'], 'project_id': project['id'],
'value': tags[0]}, 'value': tags[0]},
expected_status=http_client.BAD_REQUEST) expected_status=http.client.BAD_REQUEST)
def test_create_project_tag_over_tag_limit(self): def test_create_project_tag_over_tag_limit(self):
project, _ = self._create_project_and_tags(num_of_tags=80) project, _ = self._create_project_and_tags(num_of_tags=80)
self.put( self.put(
'/projects/%(project_id)s/tags/%(value)s' % { '/projects/%(project_id)s/tags/%(value)s' % {
'project_id': project['id'], 'project_id': project['id'],
'value': uuid.uuid4().hex}, 'value': uuid.uuid4().hex},
expected_status=http_client.BAD_REQUEST) expected_status=http.client.BAD_REQUEST)
def test_create_project_tag_name_over_character_limit(self): def test_create_project_tag_name_over_character_limit(self):
tag = 'a' * 256 tag = 'a' * 256
self.put( self.put(
'/projects/%(project_id)s/tags/%(value)s' % { '/projects/%(project_id)s/tags/%(value)s' % {
'project_id': self.project_id, 'project_id': self.project_id,
'value': tag}, 'value': tag},
expected_status=http_client.BAD_REQUEST) expected_status=http.client.BAD_REQUEST)
def test_delete_tag_invalid_project_id(self): def test_delete_tag_invalid_project_id(self):
self.delete( self.delete(
'/projects/%(project_id)s/tags/%(value)s' % { '/projects/%(project_id)s/tags/%(value)s' % {
'project_id': uuid.uuid4().hex, 'project_id': uuid.uuid4().hex,
'value': uuid.uuid4().hex}, 'value': uuid.uuid4().hex},
expected_status=http_client.NOT_FOUND) expected_status=http.client.NOT_FOUND)
def test_delete_project_tag_not_found(self): def test_delete_project_tag_not_found(self):
self.delete( self.delete(
'/projects/%(project_id)s/tags/%(value)s' % { '/projects/%(project_id)s/tags/%(value)s' % {
'project_id': self.project_id, 'project_id': self.project_id,
'value': uuid.uuid4().hex}, 'value': uuid.uuid4().hex},
expected_status=http_client.NOT_FOUND) expected_status=http.client.NOT_FOUND)
def test_list_project_tags(self): def test_list_project_tags(self):
project, tags = self._create_project_and_tags(num_of_tags=5) project, tags = self._create_project_and_tags(num_of_tags=5)
resp = self.get( resp = self.get(
'/projects/%(project_id)s/tags' % { '/projects/%(project_id)s/tags' % {
'project_id': project['id']}, 'project_id': project['id']},
expected_status=http_client.OK) expected_status=http.client.OK)
for tag in tags: for tag in tags:
self.assertIn(tag, resp.result['tags']) self.assertIn(tag, resp.result['tags'])
def test_check_if_project_tag_exists(self): def test_check_if_project_tag_exists(self):
project, tags = self._create_project_and_tags(num_of_tags=5) project, tags = self._create_project_and_tags(num_of_tags=5)
self.head( self.head(
'/projects/%(project_id)s/tags/%(value)s' % { '/projects/%(project_id)s/tags/%(value)s' % {
'project_id': project['id'], 'project_id': project['id'],
'value': tags[0]}, 'value': tags[0]},
expected_status=http_client.NO_CONTENT) expected_status=http.client.NO_CONTENT)
def test_list_project_tags_for_project_with_no_tags(self): def test_list_project_tags_for_project_with_no_tags(self):
resp = self.get( resp = self.get(
'/projects/%(project_id)s/tags' % { '/projects/%(project_id)s/tags' % {
'project_id': self.project_id}, 'project_id': self.project_id},
expected_status=http_client.OK) expected_status=http.client.OK)
self.assertEqual([], resp.result['tags']) self.assertEqual([], resp.result['tags'])
def test_check_project_with_no_tags(self): def test_check_project_with_no_tags(self):
self.head( self.head(
'/projects/%(project_id)s/tags/%(value)s' % { '/projects/%(project_id)s/tags/%(value)s' % {
'project_id': self.project_id, 'project_id': self.project_id,
'value': uuid.uuid4().hex}, 'value': uuid.uuid4().hex},
expected_status=http_client.NOT_FOUND) expected_status=http.client.NOT_FOUND)
def test_update_project_tags(self): def test_update_project_tags(self):
project, tags = self._create_project_and_tags(num_of_tags=5) project, tags = self._create_project_and_tags(num_of_tags=5)
resp = self.put( resp = self.put(
'/projects/%(project_id)s/tags' % { '/projects/%(project_id)s/tags' % {
'project_id': project['id']}, 'project_id': project['id']},
body={'tags': tags}, body={'tags': tags},
expected_status=http_client.OK) expected_status=http.client.OK)
self.assertIn(tags[1], resp.result['tags']) self.assertIn(tags[1], resp.result['tags'])
def test_update_project_tags_removes_previous_tags(self): def test_update_project_tags_removes_previous_tags(self):
tag = uuid.uuid4().hex tag = uuid.uuid4().hex
project, tags = self._create_project_and_tags(num_of_tags=5) project, tags = self._create_project_and_tags(num_of_tags=5)
self.put( self.put(
'/projects/%(project_id)s/tags/%(value)s' % { '/projects/%(project_id)s/tags/%(value)s' % {
'project_id': project['id'], 'project_id': project['id'],
'value': tag}, 'value': tag},
expected_status=http_client.CREATED) expected_status=http.client.CREATED)
resp = self.put( resp = self.put(
'/projects/%(project_id)s/tags' % { '/projects/%(project_id)s/tags' % {
'project_id': project['id']}, 'project_id': project['id']},
body={'tags': tags}, body={'tags': tags},
expected_status=http_client.OK) expected_status=http.client.OK)
self.assertNotIn(tag, resp.result['tags']) self.assertNotIn(tag, resp.result['tags'])
self.assertIn(tags[1], resp.result['tags']) self.assertIn(tags[1], resp.result['tags'])
def test_update_project_tags_unsafe_names(self): def test_update_project_tags_unsafe_names(self):
project, tags = self._create_project_and_tags(num_of_tags=5) project, tags = self._create_project_and_tags(num_of_tags=5)
invalid_chars = [',', '/'] invalid_chars = [',', '/']
for char in invalid_chars: for char in invalid_chars:
tags[0] = uuid.uuid4().hex + char tags[0] = uuid.uuid4().hex + char
self.put( self.put(
'/projects/%(project_id)s/tags' % { '/projects/%(project_id)s/tags' % {
'project_id': project['id']}, 'project_id': project['id']},
body={'tags': tags}, body={'tags': tags},
expected_status=http_client.BAD_REQUEST) expected_status=http.client.BAD_REQUEST)
def test_update_project_tags_with_too_many_tags(self): def test_update_project_tags_with_too_many_tags(self):
project, _ = self._create_project_and_tags() project, _ = self._create_project_and_tags()
tags = [uuid.uuid4().hex for i in range(81)] tags = [uuid.uuid4().hex for i in range(81)]
tags.append(uuid.uuid4().hex) tags.append(uuid.uuid4().hex)
self.put( self.put(
'/projects/%(project_id)s/tags' % {'project_id': project['id']}, '/projects/%(project_id)s/tags' % {'project_id': project['id']},
body={'tags': tags}, body={'tags': tags},
expected_status=http_client.BAD_REQUEST) expected_status=http.client.BAD_REQUEST)
def test_list_projects_by_user_with_inherited_role(self): def test_list_projects_by_user_with_inherited_role(self):
"""Ensure the cache is invalidated when creating/deleting a project.""" """Ensure the cache is invalidated when creating/deleting a project."""
domain_ref = unit.new_domain_ref() domain_ref = unit.new_domain_ref()
resp = self.post('/domains', body={'domain': domain_ref}) resp = self.post('/domains', body={'domain': domain_ref})
domain = resp.result['domain'] domain = resp.result['domain']
user_ref = unit.new_user_ref(domain_id=self.domain_id) user_ref = unit.new_user_ref(domain_id=self.domain_id)
resp = self.post('/users', body={'user': user_ref}) resp = self.post('/users', body={'user': user_ref})
user = resp.result['user'] user = resp.result['user']
skipping to change at line 1880 skipping to change at line 1879
def test_create_hierarchical_project(self): def test_create_hierarchical_project(self):
projects = self._create_projects_hierarchy() projects = self._create_projects_hierarchy()
# create grandchild project will fail. # create grandchild project will fail.
new_ref = unit.new_project_ref( new_ref = unit.new_project_ref(
domain_id=self.domain_id, domain_id=self.domain_id,
parent_id=projects[1]['project']['id']) parent_id=projects[1]['project']['id'])
self.post('/projects', self.post('/projects',
body={'project': new_ref}, body={'project': new_ref},
expected_status=http_client.FORBIDDEN) expected_status=http.client.FORBIDDEN)
 End of changes. 62 change blocks. 
62 lines changed or deleted 61 lines changed or added

Home  |  About  |  Features  |  All  |  Newest  |  Dox  |  Diffs  |  RSS Feeds  |  Screenshots  |  Comments  |  Imprint  |  Privacy  |  HTTP(S)