Merge "Functional tests migration for metadef APIs"
This commit is contained in:
@@ -12,12 +12,11 @@
|
|||||||
# limitations under the License.
|
# limitations under the License.
|
||||||
|
|
||||||
from oslo_utils.fixture import uuidsentinel as uuids
|
from oslo_utils.fixture import uuidsentinel as uuids
|
||||||
import requests
|
|
||||||
|
|
||||||
from glance.tests import functional
|
from glance.tests import functional
|
||||||
|
|
||||||
|
|
||||||
class MetadefFunctionalTestBase(functional.FunctionalTest):
|
class MetadefFunctionalTestBase(functional.SynchronousAPIBase):
|
||||||
"""A basic set of assertions and utilities for testing the metadef API."""
|
"""A basic set of assertions and utilities for testing the metadef API."""
|
||||||
|
|
||||||
def setUp(self):
|
def setUp(self):
|
||||||
@@ -61,4 +60,5 @@ class MetadefFunctionalTestBase(functional.FunctionalTest):
|
|||||||
|
|
||||||
:returns: a dictionary of the namespace in the response
|
:returns: a dictionary of the namespace in the response
|
||||||
"""
|
"""
|
||||||
return requests.post(path, headers=headers, json=namespace).json()
|
|
||||||
|
return self.api_post(path, headers, json=namespace)
|
||||||
|
@@ -16,7 +16,6 @@
|
|||||||
import http.client as http
|
import http.client as http
|
||||||
|
|
||||||
from oslo_serialization import jsonutils
|
from oslo_serialization import jsonutils
|
||||||
import requests
|
|
||||||
|
|
||||||
from glance.tests.functional.v2 import metadef_base
|
from glance.tests.functional.v2 import metadef_base
|
||||||
|
|
||||||
@@ -25,27 +24,24 @@ class TestNamespaces(metadef_base.MetadefFunctionalTestBase):
|
|||||||
|
|
||||||
def setUp(self):
|
def setUp(self):
|
||||||
super(TestNamespaces, self).setUp()
|
super(TestNamespaces, self).setUp()
|
||||||
self.cleanup()
|
self.start_server(enable_cache=False)
|
||||||
self.api_server.deployment_flavor = 'noauth'
|
|
||||||
self.start_servers(**self.__dict__.copy())
|
|
||||||
|
|
||||||
def test_namespace_lifecycle(self):
|
def test_namespace_lifecycle(self):
|
||||||
# Namespace should not exist
|
# Namespace should not exist
|
||||||
path = self._url('/v2/metadefs/namespaces/MyNamespace')
|
path = '/v2/metadefs/namespaces/MyNamespace'
|
||||||
response = requests.get(path, headers=self._headers())
|
response = self.api_get(path, headers=self._headers())
|
||||||
self.assertEqual(http.NOT_FOUND, response.status_code)
|
self.assertEqual(http.NOT_FOUND, response.status_code)
|
||||||
|
|
||||||
# Create a namespace
|
# Create a namespace
|
||||||
path = self._url('/v2/metadefs/namespaces')
|
path = '/v2/metadefs/namespaces'
|
||||||
headers = self._headers({'content-type': 'application/json'})
|
headers = self._headers({'content-type': 'application/json'})
|
||||||
namespace_name = 'MyNamespace'
|
namespace_name = 'MyNamespace'
|
||||||
data = jsonutils.dumps({
|
data = {
|
||||||
"namespace": namespace_name,
|
"namespace": namespace_name,
|
||||||
"display_name": "My User Friendly Namespace",
|
"display_name": "My User Friendly Namespace",
|
||||||
"description": "My description"
|
"description": "My description"
|
||||||
}
|
}
|
||||||
)
|
response = self.api_post(path, headers=headers, json=data)
|
||||||
response = requests.post(path, headers=headers, data=data)
|
|
||||||
self.assertEqual(http.CREATED, response.status_code)
|
self.assertEqual(http.CREATED, response.status_code)
|
||||||
namespace_loc_header = response.headers['Location']
|
namespace_loc_header = response.headers['Location']
|
||||||
|
|
||||||
@@ -80,11 +76,11 @@ class TestNamespaces(metadef_base.MetadefFunctionalTestBase):
|
|||||||
self.assertEqual(namespace[key], value, key)
|
self.assertEqual(namespace[key], value, key)
|
||||||
|
|
||||||
# Attempt to insert a duplicate
|
# Attempt to insert a duplicate
|
||||||
response = requests.post(path, headers=headers, data=data)
|
response = self.api_post(path, headers=headers, json=data)
|
||||||
self.assertEqual(http.CONFLICT, response.status_code)
|
self.assertEqual(http.CONFLICT, response.status_code)
|
||||||
|
|
||||||
# Get the namespace using the returned Location header
|
# Get the namespace using the returned Location header
|
||||||
response = requests.get(namespace_loc_header, headers=self._headers())
|
response = self.api_get(namespace_loc_header, headers=self._headers())
|
||||||
self.assertEqual(http.OK, response.status_code)
|
self.assertEqual(http.OK, response.status_code)
|
||||||
namespace = jsonutils.loads(response.text)
|
namespace = jsonutils.loads(response.text)
|
||||||
self.assertEqual(namespace_name, namespace['namespace'])
|
self.assertEqual(namespace_name, namespace['namespace'])
|
||||||
@@ -94,21 +90,19 @@ class TestNamespaces(metadef_base.MetadefFunctionalTestBase):
|
|||||||
self.assertFalse(namespace['protected'])
|
self.assertFalse(namespace['protected'])
|
||||||
|
|
||||||
# The namespace should be mutable
|
# The namespace should be mutable
|
||||||
path = self._url('/v2/metadefs/namespaces/%s' % namespace_name)
|
path = '/v2/metadefs/namespaces/%s' % namespace_name
|
||||||
media_type = 'application/json'
|
media_type = 'application/json'
|
||||||
headers = self._headers({'content-type': media_type})
|
headers = self._headers({'content-type': media_type})
|
||||||
namespace_name = "MyNamespace-UPDATED"
|
namespace_name = "MyNamespace-UPDATED"
|
||||||
data = jsonutils.dumps(
|
data = {
|
||||||
{
|
"namespace": namespace_name,
|
||||||
"namespace": namespace_name,
|
"display_name": "display_name-UPDATED",
|
||||||
"display_name": "display_name-UPDATED",
|
"description": "description-UPDATED",
|
||||||
"description": "description-UPDATED",
|
"visibility": "private", # Not changed
|
||||||
"visibility": "private", # Not changed
|
"protected": True,
|
||||||
"protected": True,
|
"owner": self.tenant2
|
||||||
"owner": self.tenant2
|
}
|
||||||
}
|
response = self.api_put(path, headers=headers, json=data)
|
||||||
)
|
|
||||||
response = requests.put(path, headers=headers, data=data)
|
|
||||||
self.assertEqual(http.OK, response.status_code, response.text)
|
self.assertEqual(http.OK, response.status_code, response.text)
|
||||||
|
|
||||||
# Returned namespace should reflect the changes
|
# Returned namespace should reflect the changes
|
||||||
@@ -121,8 +115,8 @@ class TestNamespaces(metadef_base.MetadefFunctionalTestBase):
|
|||||||
self.assertEqual(self.tenant2, namespace['owner'])
|
self.assertEqual(self.tenant2, namespace['owner'])
|
||||||
|
|
||||||
# Updates should persist across requests
|
# Updates should persist across requests
|
||||||
path = self._url('/v2/metadefs/namespaces/%s' % namespace_name)
|
path = '/v2/metadefs/namespaces/%s' % namespace_name
|
||||||
response = requests.get(path, headers=self._headers())
|
response = self.api_get(path, headers=self._headers())
|
||||||
self.assertEqual(http.OK, response.status_code)
|
self.assertEqual(http.OK, response.status_code)
|
||||||
namespace = jsonutils.loads(response.text)
|
namespace = jsonutils.loads(response.text)
|
||||||
self.assertEqual('MyNamespace-UPDATED', namespace['namespace'])
|
self.assertEqual('MyNamespace-UPDATED', namespace['namespace'])
|
||||||
@@ -133,12 +127,12 @@ class TestNamespaces(metadef_base.MetadefFunctionalTestBase):
|
|||||||
self.assertEqual(self.tenant2, namespace['owner'])
|
self.assertEqual(self.tenant2, namespace['owner'])
|
||||||
|
|
||||||
# Deletion should not work on protected namespaces
|
# Deletion should not work on protected namespaces
|
||||||
path = self._url('/v2/metadefs/namespaces/%s' % namespace_name)
|
path = '/v2/metadefs/namespaces/%s' % namespace_name
|
||||||
response = requests.delete(path, headers=self._headers())
|
response = self.api_delete(path, headers=self._headers())
|
||||||
self.assertEqual(http.FORBIDDEN, response.status_code)
|
self.assertEqual(http.FORBIDDEN, response.status_code)
|
||||||
|
|
||||||
# Unprotect namespace for deletion
|
# Unprotect namespace for deletion
|
||||||
path = self._url('/v2/metadefs/namespaces/%s' % namespace_name)
|
path = '/v2/metadefs/namespaces/%s' % namespace_name
|
||||||
media_type = 'application/json'
|
media_type = 'application/json'
|
||||||
headers = self._headers({'content-type': media_type})
|
headers = self._headers({'content-type': media_type})
|
||||||
doc = {
|
doc = {
|
||||||
@@ -149,87 +143,26 @@ class TestNamespaces(metadef_base.MetadefFunctionalTestBase):
|
|||||||
"protected": False,
|
"protected": False,
|
||||||
"owner": self.tenant2
|
"owner": self.tenant2
|
||||||
}
|
}
|
||||||
data = jsonutils.dumps(doc)
|
response = self.api_put(path, headers=headers, json=doc)
|
||||||
response = requests.put(path, headers=headers, data=data)
|
|
||||||
self.assertEqual(http.OK, response.status_code, response.text)
|
self.assertEqual(http.OK, response.status_code, response.text)
|
||||||
|
|
||||||
# Deletion should work. Deleting namespace MyNamespace
|
# Deletion should work. Deleting namespace MyNamespace
|
||||||
path = self._url('/v2/metadefs/namespaces/%s' % namespace_name)
|
path = '/v2/metadefs/namespaces/%s' % namespace_name
|
||||||
response = requests.delete(path, headers=self._headers())
|
response = self.api_delete(path, headers=self._headers())
|
||||||
self.assertEqual(http.NO_CONTENT, response.status_code)
|
self.assertEqual(http.NO_CONTENT, response.status_code)
|
||||||
|
|
||||||
# Namespace should not exist
|
# Namespace should not exist
|
||||||
path = self._url('/v2/metadefs/namespaces/MyNamespace')
|
path = '/v2/metadefs/namespaces/MyNamespace'
|
||||||
response = requests.get(path, headers=self._headers())
|
response = self.api_get(path, headers=self._headers())
|
||||||
self.assertEqual(http.NOT_FOUND, response.status_code)
|
self.assertEqual(http.NOT_FOUND, response.status_code)
|
||||||
|
|
||||||
def test_metadef_dont_accept_illegal_bodies(self):
|
|
||||||
# Namespace should not exist
|
|
||||||
path = self._url('/v2/metadefs/namespaces/bodytest')
|
|
||||||
response = requests.get(path, headers=self._headers())
|
|
||||||
self.assertEqual(http.NOT_FOUND, response.status_code)
|
|
||||||
|
|
||||||
# Create a namespace
|
|
||||||
path = self._url('/v2/metadefs/namespaces')
|
|
||||||
headers = self._headers({'content-type': 'application/json'})
|
|
||||||
namespace_name = 'bodytest'
|
|
||||||
data = jsonutils.dumps({
|
|
||||||
"namespace": namespace_name,
|
|
||||||
"display_name": "My User Friendly Namespace",
|
|
||||||
"description": "My description"
|
|
||||||
}
|
|
||||||
)
|
|
||||||
response = requests.post(path, headers=headers, data=data)
|
|
||||||
self.assertEqual(http.CREATED, response.status_code)
|
|
||||||
|
|
||||||
# Test all the urls that supply data
|
|
||||||
data_urls = [
|
|
||||||
'/v2/schemas/metadefs/namespace',
|
|
||||||
'/v2/schemas/metadefs/namespaces',
|
|
||||||
'/v2/schemas/metadefs/resource_type',
|
|
||||||
'/v2/schemas/metadefs/resource_types',
|
|
||||||
'/v2/schemas/metadefs/property',
|
|
||||||
'/v2/schemas/metadefs/properties',
|
|
||||||
'/v2/schemas/metadefs/object',
|
|
||||||
'/v2/schemas/metadefs/objects',
|
|
||||||
'/v2/schemas/metadefs/tag',
|
|
||||||
'/v2/schemas/metadefs/tags',
|
|
||||||
'/v2/metadefs/resource_types',
|
|
||||||
]
|
|
||||||
for value in data_urls:
|
|
||||||
path = self._url(value)
|
|
||||||
data = jsonutils.dumps(["body"])
|
|
||||||
response = requests.get(path, headers=self._headers(), data=data)
|
|
||||||
self.assertEqual(http.BAD_REQUEST, response.status_code)
|
|
||||||
|
|
||||||
# Put the namespace into the url
|
|
||||||
test_urls = [
|
|
||||||
('/v2/metadefs/namespaces/%s/resource_types', 'get'),
|
|
||||||
('/v2/metadefs/namespaces/%s/resource_types/type', 'delete'),
|
|
||||||
('/v2/metadefs/namespaces/%s', 'get'),
|
|
||||||
('/v2/metadefs/namespaces/%s', 'delete'),
|
|
||||||
('/v2/metadefs/namespaces/%s/objects/name', 'get'),
|
|
||||||
('/v2/metadefs/namespaces/%s/objects/name', 'delete'),
|
|
||||||
('/v2/metadefs/namespaces/%s/properties', 'get'),
|
|
||||||
('/v2/metadefs/namespaces/%s/tags/test', 'get'),
|
|
||||||
('/v2/metadefs/namespaces/%s/tags/test', 'post'),
|
|
||||||
('/v2/metadefs/namespaces/%s/tags/test', 'delete'),
|
|
||||||
]
|
|
||||||
|
|
||||||
for link, method in test_urls:
|
|
||||||
path = self._url(link % namespace_name)
|
|
||||||
data = jsonutils.dumps(["body"])
|
|
||||||
response = getattr(requests, method)(
|
|
||||||
path, headers=self._headers(), data=data)
|
|
||||||
self.assertEqual(http.BAD_REQUEST, response.status_code)
|
|
||||||
|
|
||||||
def _update_namespace(self, path, headers, data):
|
def _update_namespace(self, path, headers, data):
|
||||||
# The namespace should be mutable
|
# The namespace should be mutable
|
||||||
response = requests.put(path, headers=headers, json=data)
|
response = self.api_put(path, headers=headers, json=data)
|
||||||
self.assertEqual(http.OK, response.status_code, response.text)
|
self.assertEqual(http.OK, response.status_code, response.text)
|
||||||
|
|
||||||
# Returned namespace should reflect the changes
|
# Returned namespace should reflect the changes
|
||||||
namespace = response.json()
|
namespace = jsonutils.loads(response.text)
|
||||||
expected_namespace = {
|
expected_namespace = {
|
||||||
"namespace": data['namespace'],
|
"namespace": data['namespace'],
|
||||||
"display_name": data['display_name'],
|
"display_name": data['display_name'],
|
||||||
@@ -245,10 +178,10 @@ class TestNamespaces(metadef_base.MetadefFunctionalTestBase):
|
|||||||
self.assertEqual(namespace, expected_namespace)
|
self.assertEqual(namespace, expected_namespace)
|
||||||
|
|
||||||
# Updates should persist across requests
|
# Updates should persist across requests
|
||||||
path = self._url('/v2/metadefs/namespaces/%s' % namespace['namespace'])
|
path = '/v2/metadefs/namespaces/%s' % namespace['namespace']
|
||||||
response = requests.get(path, headers=self._headers())
|
response = self.api_get(path, headers=self._headers())
|
||||||
self.assertEqual(http.OK, response.status_code)
|
self.assertEqual(http.OK, response.status_code)
|
||||||
namespace = response.json()
|
namespace = jsonutils.loads(response.text)
|
||||||
namespace.pop('created_at')
|
namespace.pop('created_at')
|
||||||
namespace.pop('updated_at')
|
namespace.pop('updated_at')
|
||||||
self.assertEqual(namespace, expected_namespace)
|
self.assertEqual(namespace, expected_namespace)
|
||||||
@@ -257,7 +190,7 @@ class TestNamespaces(metadef_base.MetadefFunctionalTestBase):
|
|||||||
|
|
||||||
def test_role_based_namespace_lifecycle(self):
|
def test_role_based_namespace_lifecycle(self):
|
||||||
# Create public and private namespaces for tenant1 and tenant2
|
# Create public and private namespaces for tenant1 and tenant2
|
||||||
path = self._url('/v2/metadefs/namespaces')
|
path = '/v2/metadefs/namespaces'
|
||||||
headers = self._headers({'content-type': 'application/json'})
|
headers = self._headers({'content-type': 'application/json'})
|
||||||
tenant_namespaces = dict()
|
tenant_namespaces = dict()
|
||||||
for tenant in [self.tenant1, self.tenant2]:
|
for tenant in [self.tenant1, self.tenant2]:
|
||||||
@@ -272,6 +205,7 @@ class TestNamespaces(metadef_base.MetadefFunctionalTestBase):
|
|||||||
}
|
}
|
||||||
namespace = self.create_namespace(path, headers,
|
namespace = self.create_namespace(path, headers,
|
||||||
namespace_data)
|
namespace_data)
|
||||||
|
namespace = jsonutils.loads(namespace.text)
|
||||||
self.assertNamespacesEqual(namespace, namespace_data)
|
self.assertNamespacesEqual(namespace, namespace_data)
|
||||||
tenant_namespaces.setdefault(tenant, list())
|
tenant_namespaces.setdefault(tenant, list())
|
||||||
tenant_namespaces[tenant].append(namespace)
|
tenant_namespaces[tenant].append(namespace)
|
||||||
@@ -294,12 +228,12 @@ class TestNamespaces(metadef_base.MetadefFunctionalTestBase):
|
|||||||
# Check Tenant 1 and Tenant 2 will be able to see total 3 namespaces
|
# Check Tenant 1 and Tenant 2 will be able to see total 3 namespaces
|
||||||
# (two of own and 1 public of other tenant)
|
# (two of own and 1 public of other tenant)
|
||||||
for tenant in [self.tenant1, self.tenant2]:
|
for tenant in [self.tenant1, self.tenant2]:
|
||||||
path = self._url('/v2/metadefs/namespaces')
|
path = '/v2/metadefs/namespaces'
|
||||||
headers = self._headers({'X-Tenant-Id': tenant,
|
headers = self._headers({'X-Tenant-Id': tenant,
|
||||||
'X-Roles': 'reader,member'})
|
'X-Roles': 'reader,member'})
|
||||||
response = requests.get(path, headers=headers)
|
response = self.api_get(path, headers=headers)
|
||||||
self.assertEqual(http.OK, response.status_code)
|
self.assertEqual(http.OK, response.status_code)
|
||||||
namespaces = response.json()['namespaces']
|
namespaces = jsonutils.loads(response.text)['namespaces']
|
||||||
expected_namespaces = _get_expected_namespaces(tenant)
|
expected_namespaces = _get_expected_namespaces(tenant)
|
||||||
self.assertEqual(sorted(x['namespace'] for x in namespaces),
|
self.assertEqual(sorted(x['namespace'] for x in namespaces),
|
||||||
sorted(expected_namespaces))
|
sorted(expected_namespaces))
|
||||||
@@ -308,10 +242,8 @@ class TestNamespaces(metadef_base.MetadefFunctionalTestBase):
|
|||||||
headers = self._headers({'X-Tenant-Id': tenant,
|
headers = self._headers({'X-Tenant-Id': tenant,
|
||||||
'X-Roles': 'reader,member'})
|
'X-Roles': 'reader,member'})
|
||||||
for namespace in namespaces:
|
for namespace in namespaces:
|
||||||
path = self._url(
|
path = '/v2/metadefs/namespaces/%s' % namespace['namespace']
|
||||||
'/v2/metadefs/namespaces/%s' % namespace['namespace'])
|
response = self.api_get(path, headers=headers)
|
||||||
headers = headers
|
|
||||||
response = requests.get(path, headers=headers)
|
|
||||||
if namespace['visibility'] == 'public':
|
if namespace['visibility'] == 'public':
|
||||||
self.assertEqual(http.OK, response.status_code)
|
self.assertEqual(http.OK, response.status_code)
|
||||||
else:
|
else:
|
||||||
@@ -338,14 +270,13 @@ class TestNamespaces(metadef_base.MetadefFunctionalTestBase):
|
|||||||
"protected": True, # changed
|
"protected": True, # changed
|
||||||
"owner": namespace["owner"] # Not changed
|
"owner": namespace["owner"] # Not changed
|
||||||
}
|
}
|
||||||
path = self._url(
|
path = '/v2/metadefs/namespaces/%s' % namespace['namespace']
|
||||||
'/v2/metadefs/namespaces/%s' % namespace['namespace'])
|
|
||||||
headers = self._headers({
|
headers = self._headers({
|
||||||
'X-Tenant-Id': namespace['owner'],
|
'X-Tenant-Id': namespace['owner'],
|
||||||
})
|
})
|
||||||
# Update namespace should fail with non admin role
|
# Update namespace should fail with non admin role
|
||||||
headers['X-Roles'] = "reader,member"
|
headers['X-Roles'] = "reader,member"
|
||||||
response = requests.put(path, headers=headers, json=data)
|
response = self.api_put(path, headers=headers, json=data)
|
||||||
self.assertEqual(http.FORBIDDEN, response.status_code)
|
self.assertEqual(http.FORBIDDEN, response.status_code)
|
||||||
|
|
||||||
# Should work with admin role
|
# Should work with admin role
|
||||||
@@ -353,16 +284,14 @@ class TestNamespaces(metadef_base.MetadefFunctionalTestBase):
|
|||||||
namespace = self._update_namespace(path, headers, data)
|
namespace = self._update_namespace(path, headers, data)
|
||||||
|
|
||||||
# Deletion should fail as namespaces are protected now
|
# Deletion should fail as namespaces are protected now
|
||||||
path = self._url(
|
path = '/v2/metadefs/namespaces/%s' % namespace['namespace']
|
||||||
'/v2/metadefs/namespaces/%s' % namespace['namespace'])
|
|
||||||
headers['X-Roles'] = "admin"
|
headers['X-Roles'] = "admin"
|
||||||
response = requests.delete(path, headers=headers)
|
response = self.api_delete(path, headers=headers)
|
||||||
self.assertEqual(http.FORBIDDEN, response.status_code)
|
self.assertEqual(http.FORBIDDEN, response.status_code)
|
||||||
|
|
||||||
# Deletion should not be allowed for non admin roles
|
# Deletion should not be allowed for non admin roles
|
||||||
path = self._url(
|
path = '/v2/metadefs/namespaces/%s' % namespace['namespace']
|
||||||
'/v2/metadefs/namespaces/%s' % namespace['namespace'])
|
response = self.api_delete(
|
||||||
response = requests.delete(
|
|
||||||
path, headers=self._headers({
|
path, headers=self._headers({
|
||||||
'X-Roles': 'reader,member',
|
'X-Roles': 'reader,member',
|
||||||
'X-Tenant-Id': namespace['owner']
|
'X-Tenant-Id': namespace['owner']
|
||||||
@@ -372,29 +301,26 @@ class TestNamespaces(metadef_base.MetadefFunctionalTestBase):
|
|||||||
# Unprotect the namespaces before deletion
|
# Unprotect the namespaces before deletion
|
||||||
headers = self._headers()
|
headers = self._headers()
|
||||||
for namespace in total_ns:
|
for namespace in total_ns:
|
||||||
path = self._url(
|
path = '/v2/metadefs/namespaces/%s' % namespace['namespace']
|
||||||
'/v2/metadefs/namespaces/%s' % namespace['namespace'])
|
|
||||||
headers = headers
|
|
||||||
data = {
|
data = {
|
||||||
"namespace": namespace['namespace'],
|
"namespace": namespace['namespace'],
|
||||||
"protected": False,
|
"protected": False,
|
||||||
}
|
}
|
||||||
response = requests.put(path, headers=headers, json=data)
|
response = self.api_put(path, headers=headers, json=data)
|
||||||
self.assertEqual(http.OK, response.status_code)
|
self.assertEqual(http.OK, response.status_code)
|
||||||
|
|
||||||
# Get updated namespace set again
|
# Get updated namespace set again
|
||||||
path = self._url('/v2/metadefs/namespaces')
|
path = '/v2/metadefs/namespaces'
|
||||||
response = requests.get(path, headers=headers)
|
response = self.api_get(path, headers=headers)
|
||||||
self.assertEqual(http.OK, response.status_code)
|
self.assertEqual(http.OK, response.status_code)
|
||||||
self.assertFalse(namespace['protected'])
|
self.assertFalse(namespace['protected'])
|
||||||
namespaces = response.json()['namespaces']
|
namespaces = jsonutils.loads(response.text)['namespaces']
|
||||||
|
|
||||||
# Verify that deletion is not allowed for unprotected namespaces with
|
# Verify that deletion is not allowed for unprotected namespaces with
|
||||||
# non admin role
|
# non admin role
|
||||||
for namespace in namespaces:
|
for namespace in namespaces:
|
||||||
path = self._url(
|
path = '/v2/metadefs/namespaces/%s' % namespace['namespace']
|
||||||
'/v2/metadefs/namespaces/%s' % namespace['namespace'])
|
response = self.api_delete(
|
||||||
response = requests.delete(
|
|
||||||
path, headers=self._headers({
|
path, headers=self._headers({
|
||||||
'X-Roles': 'reader,member',
|
'X-Roles': 'reader,member',
|
||||||
'X-Tenant-Id': namespace['owner']
|
'X-Tenant-Id': namespace['owner']
|
||||||
@@ -403,13 +329,11 @@ class TestNamespaces(metadef_base.MetadefFunctionalTestBase):
|
|||||||
|
|
||||||
# Delete namespaces of all tenants
|
# Delete namespaces of all tenants
|
||||||
for namespace in total_ns:
|
for namespace in total_ns:
|
||||||
path = self._url(
|
path = '/v2/metadefs/namespaces/%s' % namespace['namespace']
|
||||||
'/v2/metadefs/namespaces/%s' % namespace['namespace'])
|
response = self.api_delete(path, headers=headers)
|
||||||
response = requests.delete(path, headers=headers)
|
|
||||||
self.assertEqual(http.NO_CONTENT, response.status_code)
|
self.assertEqual(http.NO_CONTENT, response.status_code)
|
||||||
|
|
||||||
# Deleted namespace should not be returned
|
# Deleted namespace should not be returned
|
||||||
path = self._url(
|
path = '/v2/metadefs/namespaces/%s' % namespace['namespace']
|
||||||
'/v2/metadefs/namespaces/%s' % namespace['namespace'])
|
response = self.api_get(path, headers=headers)
|
||||||
response = requests.get(path, headers=headers)
|
|
||||||
self.assertEqual(http.NOT_FOUND, response.status_code)
|
self.assertEqual(http.NOT_FOUND, response.status_code)
|
||||||
|
@@ -16,7 +16,6 @@
|
|||||||
import http.client as http
|
import http.client as http
|
||||||
|
|
||||||
from oslo_serialization import jsonutils
|
from oslo_serialization import jsonutils
|
||||||
import requests
|
|
||||||
|
|
||||||
from glance.tests.functional.v2 import metadef_base
|
from glance.tests.functional.v2 import metadef_base
|
||||||
|
|
||||||
@@ -25,21 +24,19 @@ class TestMetadefObjects(metadef_base.MetadefFunctionalTestBase):
|
|||||||
|
|
||||||
def setUp(self):
|
def setUp(self):
|
||||||
super(TestMetadefObjects, self).setUp()
|
super(TestMetadefObjects, self).setUp()
|
||||||
self.cleanup()
|
self.start_server(enable_cache=False)
|
||||||
self.api_server.deployment_flavor = 'noauth'
|
|
||||||
self.start_servers(**self.__dict__.copy())
|
|
||||||
|
|
||||||
def test_metadata_objects_lifecycle(self):
|
def test_metadata_objects_lifecycle(self):
|
||||||
# Namespace should not exist
|
# Namespace should not exist
|
||||||
path = self._url('/v2/metadefs/namespaces/MyNamespace')
|
path = '/v2/metadefs/namespaces/MyNamespace'
|
||||||
response = requests.get(path, headers=self._headers())
|
response = self.api_get(path, headers=self._headers())
|
||||||
self.assertEqual(http.NOT_FOUND, response.status_code)
|
self.assertEqual(http.NOT_FOUND, response.status_code)
|
||||||
|
|
||||||
# Create a namespace
|
# Create a namespace
|
||||||
path = self._url('/v2/metadefs/namespaces')
|
path = '/v2/metadefs/namespaces'
|
||||||
headers = self._headers({'content-type': 'application/json'})
|
headers = self._headers({'content-type': 'application/json'})
|
||||||
namespace_name = 'MyNamespace'
|
namespace_name = 'MyNamespace'
|
||||||
data = jsonutils.dumps({
|
data = {
|
||||||
"namespace": namespace_name,
|
"namespace": namespace_name,
|
||||||
"display_name": "My User Friendly Namespace",
|
"display_name": "My User Friendly Namespace",
|
||||||
"description": "My description",
|
"description": "My description",
|
||||||
@@ -47,58 +44,55 @@ class TestMetadefObjects(metadef_base.MetadefFunctionalTestBase):
|
|||||||
"protected": False,
|
"protected": False,
|
||||||
"owner": "The Test Owner"
|
"owner": "The Test Owner"
|
||||||
}
|
}
|
||||||
)
|
response = self.api_post(path, headers=headers, json=data)
|
||||||
response = requests.post(path, headers=headers, data=data)
|
|
||||||
self.assertEqual(http.CREATED, response.status_code)
|
self.assertEqual(http.CREATED, response.status_code)
|
||||||
|
|
||||||
# Metadata objects should not exist
|
# Metadata objects should not exist
|
||||||
path = self._url('/v2/metadefs/namespaces/MyNamespace/objects/object1')
|
path = '/v2/metadefs/namespaces/MyNamespace/objects/object1'
|
||||||
response = requests.get(path, headers=self._headers())
|
response = self.api_get(path, headers=self._headers())
|
||||||
self.assertEqual(http.NOT_FOUND, response.status_code)
|
self.assertEqual(http.NOT_FOUND, response.status_code)
|
||||||
|
|
||||||
# Create a object
|
# Create a object
|
||||||
path = self._url('/v2/metadefs/namespaces/MyNamespace/objects')
|
path = '/v2/metadefs/namespaces/MyNamespace/objects'
|
||||||
headers = self._headers({'content-type': 'application/json'})
|
headers = self._headers({'content-type': 'application/json'})
|
||||||
metadata_object_name = "object1"
|
metadata_object_name = "object1"
|
||||||
data = jsonutils.dumps(
|
data = {
|
||||||
{
|
"name": metadata_object_name,
|
||||||
"name": metadata_object_name,
|
"description": "object1 description.",
|
||||||
"description": "object1 description.",
|
"required": [
|
||||||
"required": [
|
"property1"
|
||||||
"property1"
|
],
|
||||||
],
|
"properties": {
|
||||||
"properties": {
|
"property1": {
|
||||||
"property1": {
|
"type": "integer",
|
||||||
"type": "integer",
|
"title": "property1",
|
||||||
"title": "property1",
|
"description": "property1 description",
|
||||||
"description": "property1 description",
|
"operators": ["<all-in>"],
|
||||||
"operators": ["<all-in>"],
|
"default": 100,
|
||||||
"default": 100,
|
"minimum": 100,
|
||||||
"minimum": 100,
|
"maximum": 30000369
|
||||||
"maximum": 30000369
|
},
|
||||||
},
|
"property2": {
|
||||||
"property2": {
|
"type": "string",
|
||||||
"type": "string",
|
"title": "property2",
|
||||||
"title": "property2",
|
"description": "property2 description ",
|
||||||
"description": "property2 description ",
|
"default": "value2",
|
||||||
"default": "value2",
|
"minLength": 2,
|
||||||
"minLength": 2,
|
"maxLength": 50
|
||||||
"maxLength": 50
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
)
|
}
|
||||||
response = requests.post(path, headers=headers, data=data)
|
response = self.api_post(path, headers=headers, json=data)
|
||||||
self.assertEqual(http.CREATED, response.status_code)
|
self.assertEqual(http.CREATED, response.status_code)
|
||||||
|
|
||||||
# Attempt to insert a duplicate
|
# Attempt to insert a duplicate
|
||||||
response = requests.post(path, headers=headers, data=data)
|
response = self.api_post(path, headers=headers, json=data)
|
||||||
self.assertEqual(http.CONFLICT, response.status_code)
|
self.assertEqual(http.CONFLICT, response.status_code)
|
||||||
|
|
||||||
# Get the metadata object created above
|
# Get the metadata object created above
|
||||||
path = self._url('/v2/metadefs/namespaces/%s/objects/%s' %
|
path = '/v2/metadefs/namespaces/%s/objects/%s' % (
|
||||||
(namespace_name, metadata_object_name))
|
namespace_name, metadata_object_name)
|
||||||
response = requests.get(path,
|
response = self.api_get(path,
|
||||||
headers=self._headers())
|
headers=self._headers())
|
||||||
self.assertEqual(http.OK, response.status_code)
|
self.assertEqual(http.OK, response.status_code)
|
||||||
metadata_object = jsonutils.loads(response.text)
|
metadata_object = jsonutils.loads(response.text)
|
||||||
@@ -166,40 +160,38 @@ class TestMetadefObjects(metadef_base.MetadefFunctionalTestBase):
|
|||||||
)
|
)
|
||||||
|
|
||||||
# The metadata_object should be mutable
|
# The metadata_object should be mutable
|
||||||
path = self._url('/v2/metadefs/namespaces/%s/objects/%s' %
|
path = '/v2/metadefs/namespaces/%s/objects/%s' % (
|
||||||
(namespace_name, metadata_object_name))
|
namespace_name, metadata_object_name)
|
||||||
media_type = 'application/json'
|
media_type = 'application/json'
|
||||||
headers = self._headers({'content-type': media_type})
|
headers = self._headers({'content-type': media_type})
|
||||||
metadata_object_name = "object1-UPDATED"
|
metadata_object_name = "object1-UPDATED"
|
||||||
data = jsonutils.dumps(
|
data = {
|
||||||
{
|
"name": metadata_object_name,
|
||||||
"name": metadata_object_name,
|
"description": "desc-UPDATED",
|
||||||
"description": "desc-UPDATED",
|
"required": [
|
||||||
"required": [
|
"property2"
|
||||||
"property2"
|
],
|
||||||
],
|
"properties": {
|
||||||
"properties": {
|
'property1': {
|
||||||
'property1': {
|
'type': 'integer',
|
||||||
'type': 'integer',
|
"title": "property1",
|
||||||
"title": "property1",
|
'description': 'p1 desc-UPDATED',
|
||||||
'description': 'p1 desc-UPDATED',
|
'default': 500,
|
||||||
'default': 500,
|
'minimum': 500,
|
||||||
'minimum': 500,
|
'maximum': 1369
|
||||||
'maximum': 1369
|
},
|
||||||
},
|
"property2": {
|
||||||
"property2": {
|
"type": "string",
|
||||||
"type": "string",
|
"title": "property2",
|
||||||
"title": "property2",
|
"description": "p2 desc-UPDATED",
|
||||||
"description": "p2 desc-UPDATED",
|
'operators': ['<or>'],
|
||||||
'operators': ['<or>'],
|
"default": "value2-UPDATED",
|
||||||
"default": "value2-UPDATED",
|
"minLength": 5,
|
||||||
"minLength": 5,
|
"maxLength": 150
|
||||||
"maxLength": 150
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
)
|
}
|
||||||
response = requests.put(path, headers=headers, data=data)
|
response = self.api_put(path, headers=headers, json=data)
|
||||||
self.assertEqual(http.OK, response.status_code, response.text)
|
self.assertEqual(http.OK, response.status_code, response.text)
|
||||||
|
|
||||||
# Returned metadata_object should reflect the changes
|
# Returned metadata_object should reflect the changes
|
||||||
@@ -222,9 +214,9 @@ class TestMetadefObjects(metadef_base.MetadefFunctionalTestBase):
|
|||||||
self.assertEqual(150, updated_property2['maxLength'])
|
self.assertEqual(150, updated_property2['maxLength'])
|
||||||
|
|
||||||
# Updates should persist across requests
|
# Updates should persist across requests
|
||||||
path = self._url('/v2/metadefs/namespaces/%s/objects/%s' %
|
path = '/v2/metadefs/namespaces/%s/objects/%s' % (
|
||||||
(namespace_name, metadata_object_name))
|
namespace_name, metadata_object_name)
|
||||||
response = requests.get(path, headers=self._headers())
|
response = self.api_get(path, headers=self._headers())
|
||||||
self.assertEqual(200, response.status_code)
|
self.assertEqual(200, response.status_code)
|
||||||
self.assertEqual('object1-UPDATED', metadata_object['name'])
|
self.assertEqual('object1-UPDATED', metadata_object['name'])
|
||||||
self.assertEqual('desc-UPDATED', metadata_object['description'])
|
self.assertEqual('desc-UPDATED', metadata_object['description'])
|
||||||
@@ -244,15 +236,15 @@ class TestMetadefObjects(metadef_base.MetadefFunctionalTestBase):
|
|||||||
self.assertEqual(150, updated_property2['maxLength'])
|
self.assertEqual(150, updated_property2['maxLength'])
|
||||||
|
|
||||||
# Deletion of metadata_object object1
|
# Deletion of metadata_object object1
|
||||||
path = self._url('/v2/metadefs/namespaces/%s/objects/%s' %
|
path = '/v2/metadefs/namespaces/%s/objects/%s' % (
|
||||||
(namespace_name, metadata_object_name))
|
namespace_name, metadata_object_name)
|
||||||
response = requests.delete(path, headers=self._headers())
|
response = self.api_delete(path, headers=self._headers())
|
||||||
self.assertEqual(http.NO_CONTENT, response.status_code)
|
self.assertEqual(http.NO_CONTENT, response.status_code)
|
||||||
|
|
||||||
# metadata_object object1 should not exist
|
# metadata_object object1 should not exist
|
||||||
path = self._url('/v2/metadefs/namespaces/%s/objects/%s' %
|
path = '/v2/metadefs/namespaces/%s/objects/%s' % (
|
||||||
(namespace_name, metadata_object_name))
|
namespace_name, metadata_object_name)
|
||||||
response = requests.get(path, headers=self._headers())
|
response = self.api_get(path, headers=self._headers())
|
||||||
self.assertEqual(http.NOT_FOUND, response.status_code)
|
self.assertEqual(http.NOT_FOUND, response.status_code)
|
||||||
|
|
||||||
def _create_object(self, namespaces):
|
def _create_object(self, namespaces):
|
||||||
@@ -273,11 +265,11 @@ class TestMetadefObjects(metadef_base.MetadefFunctionalTestBase):
|
|||||||
},
|
},
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
path = self._url('/v2/metadefs/namespaces/%s/objects' %
|
path = ('/v2/metadefs/namespaces/%s/'
|
||||||
namespace['namespace'])
|
'objects') % namespace['namespace']
|
||||||
response = requests.post(path, headers=headers, json=data)
|
response = self.api_post(path, headers=headers, json=data)
|
||||||
self.assertEqual(http.CREATED, response.status_code)
|
self.assertEqual(http.CREATED, response.status_code)
|
||||||
obj_metadata = response.json()
|
obj_metadata = jsonutils.loads(response.text)
|
||||||
metadef_objects = dict()
|
metadef_objects = dict()
|
||||||
metadef_objects[namespace['namespace']] = obj_metadata['name']
|
metadef_objects[namespace['namespace']] = obj_metadata['name']
|
||||||
objects.append(metadef_objects)
|
objects.append(metadef_objects)
|
||||||
@@ -285,7 +277,7 @@ class TestMetadefObjects(metadef_base.MetadefFunctionalTestBase):
|
|||||||
return objects
|
return objects
|
||||||
|
|
||||||
def _update_object(self, path, headers, data, namespace):
|
def _update_object(self, path, headers, data, namespace):
|
||||||
response = requests.put(path, headers=headers, json=data)
|
response = self.api_put(path, headers=headers, json=data)
|
||||||
self.assertEqual(http.OK, response.status_code, response.text)
|
self.assertEqual(http.OK, response.status_code, response.text)
|
||||||
|
|
||||||
expected_object = {
|
expected_object = {
|
||||||
@@ -298,21 +290,21 @@ class TestMetadefObjects(metadef_base.MetadefFunctionalTestBase):
|
|||||||
data['name'])
|
data['name'])
|
||||||
}
|
}
|
||||||
# Returned metadata_object should reflect the changes
|
# Returned metadata_object should reflect the changes
|
||||||
metadata_object = response.json()
|
metadata_object = jsonutils.loads(response.text)
|
||||||
metadata_object.pop('created_at')
|
metadata_object.pop('created_at')
|
||||||
metadata_object.pop('updated_at')
|
metadata_object.pop('updated_at')
|
||||||
self.assertEqual(metadata_object, expected_object)
|
self.assertEqual(metadata_object, expected_object)
|
||||||
|
|
||||||
# Updates should persist across requests
|
# Updates should persist across requests
|
||||||
response = requests.get(path, headers=self._headers())
|
response = self.api_get(path, headers=self._headers())
|
||||||
metadata_object = response.json()
|
metadata_object = jsonutils.loads(response.text)
|
||||||
metadata_object.pop('created_at')
|
metadata_object.pop('created_at')
|
||||||
metadata_object.pop('updated_at')
|
metadata_object.pop('updated_at')
|
||||||
self.assertEqual(metadata_object, expected_object)
|
self.assertEqual(metadata_object, expected_object)
|
||||||
|
|
||||||
def test_role_base_metadata_objects_lifecycle(self):
|
def test_role_base_metadata_objects_lifecycle(self):
|
||||||
# Create public and private namespaces for tenant1 and tenant2
|
# Create public and private namespaces for tenant1 and tenant2
|
||||||
path = self._url('/v2/metadefs/namespaces')
|
path = '/v2/metadefs/namespaces'
|
||||||
headers = self._headers({'content-type': 'application/json'})
|
headers = self._headers({'content-type': 'application/json'})
|
||||||
tenant1_namespaces = []
|
tenant1_namespaces = []
|
||||||
tenant2_namespaces = []
|
tenant2_namespaces = []
|
||||||
@@ -328,6 +320,7 @@ class TestMetadefObjects(metadef_base.MetadefFunctionalTestBase):
|
|||||||
}
|
}
|
||||||
namespace = self.create_namespace(path, headers,
|
namespace = self.create_namespace(path, headers,
|
||||||
namespace_data)
|
namespace_data)
|
||||||
|
namespace = jsonutils.loads(namespace.text)
|
||||||
self.assertNamespacesEqual(namespace, namespace_data)
|
self.assertNamespacesEqual(namespace, namespace_data)
|
||||||
if tenant == self.tenant1:
|
if tenant == self.tenant1:
|
||||||
tenant1_namespaces.append(namespace)
|
tenant1_namespaces.append(namespace)
|
||||||
@@ -344,10 +337,9 @@ class TestMetadefObjects(metadef_base.MetadefFunctionalTestBase):
|
|||||||
'X-Roles': 'reader,member'})
|
'X-Roles': 'reader,member'})
|
||||||
for obj in objects:
|
for obj in objects:
|
||||||
for namespace, object_name in obj.items():
|
for namespace, object_name in obj.items():
|
||||||
path = self._url('/v2/metadefs/namespaces/%s/objects/%s' %
|
path = '/v2/metadefs/namespaces/%s/objects/%s' % (
|
||||||
(namespace, object_name))
|
namespace, object_name)
|
||||||
headers = headers
|
response = self.api_get(path, headers=headers)
|
||||||
response = requests.get(path, headers=headers)
|
|
||||||
if namespace.split('_')[1] == 'public':
|
if namespace.split('_')[1] == 'public':
|
||||||
expected = http.OK
|
expected = http.OK
|
||||||
else:
|
else:
|
||||||
@@ -355,12 +347,11 @@ class TestMetadefObjects(metadef_base.MetadefFunctionalTestBase):
|
|||||||
|
|
||||||
self.assertEqual(expected, response.status_code)
|
self.assertEqual(expected, response.status_code)
|
||||||
|
|
||||||
path = self._url(
|
path = '/v2/metadefs/namespaces/%s/objects' % namespace
|
||||||
'/v2/metadefs/namespaces/%s/objects' % namespace)
|
response = self.api_get(path, headers=headers)
|
||||||
response = requests.get(path, headers=headers)
|
|
||||||
self.assertEqual(expected, response.status_code)
|
self.assertEqual(expected, response.status_code)
|
||||||
if expected == http.OK:
|
if expected == http.OK:
|
||||||
resp_objs = response.json()['objects']
|
resp_objs = jsonutils.loads(response.text)['objects']
|
||||||
self.assertEqual(
|
self.assertEqual(
|
||||||
sorted(obj.values()),
|
sorted(obj.values()),
|
||||||
sorted([x['name'] for x in resp_objs]))
|
sorted([x['name'] for x in resp_objs]))
|
||||||
@@ -392,10 +383,10 @@ class TestMetadefObjects(metadef_base.MetadefFunctionalTestBase):
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
# Update object should fail with non admin role
|
# Update object should fail with non admin role
|
||||||
path = self._url('/v2/metadefs/namespaces/%s/objects/%s' %
|
path = '/v2/metadefs/namespaces/%s/objects/%s' % (
|
||||||
(namespace, object_name))
|
namespace, object_name)
|
||||||
headers['X-Roles'] = "reader,member"
|
headers['X-Roles'] = "reader,member"
|
||||||
response = requests.put(path, headers=headers, json=data)
|
response = self.api_put(path, headers=headers, json=data)
|
||||||
self.assertEqual(http.FORBIDDEN, response.status_code)
|
self.assertEqual(http.FORBIDDEN, response.status_code)
|
||||||
|
|
||||||
# Should work with admin role
|
# Should work with admin role
|
||||||
@@ -406,9 +397,9 @@ class TestMetadefObjects(metadef_base.MetadefFunctionalTestBase):
|
|||||||
# Delete object should not be allowed to non admin role
|
# Delete object should not be allowed to non admin role
|
||||||
for obj in total_objects:
|
for obj in total_objects:
|
||||||
for namespace, object_name in obj.items():
|
for namespace, object_name in obj.items():
|
||||||
path = self._url('/v2/metadefs/namespaces/%s/objects/%s' %
|
path = '/v2/metadefs/namespaces/%s/objects/%s' % (
|
||||||
(namespace, object_name))
|
namespace, object_name)
|
||||||
response = requests.delete(
|
response = self.api_delete(
|
||||||
path, headers=self._headers({
|
path, headers=self._headers({
|
||||||
'X-Roles': 'reader,member',
|
'X-Roles': 'reader,member',
|
||||||
'X-Tenant-Id': namespace.split('_')[0]
|
'X-Tenant-Id': namespace.split('_')[0]
|
||||||
@@ -419,11 +410,11 @@ class TestMetadefObjects(metadef_base.MetadefFunctionalTestBase):
|
|||||||
headers = self._headers()
|
headers = self._headers()
|
||||||
for obj in total_objects:
|
for obj in total_objects:
|
||||||
for namespace, object_name in obj.items():
|
for namespace, object_name in obj.items():
|
||||||
path = self._url('/v2/metadefs/namespaces/%s/objects/%s' %
|
path = '/v2/metadefs/namespaces/%s/objects/%s' % (
|
||||||
(namespace, object_name))
|
namespace, object_name)
|
||||||
response = requests.delete(path, headers=headers)
|
response = self.api_delete(path, headers=headers)
|
||||||
self.assertEqual(http.NO_CONTENT, response.status_code)
|
self.assertEqual(http.NO_CONTENT, response.status_code)
|
||||||
|
|
||||||
# Deleted objects should not be exist
|
# Deleted objects should not exist
|
||||||
response = requests.get(path, headers=headers)
|
response = self.api_get(path, headers=headers)
|
||||||
self.assertEqual(http.NOT_FOUND, response.status_code)
|
self.assertEqual(http.NOT_FOUND, response.status_code)
|
||||||
|
@@ -16,7 +16,6 @@
|
|||||||
import http.client as http
|
import http.client as http
|
||||||
|
|
||||||
from oslo_serialization import jsonutils
|
from oslo_serialization import jsonutils
|
||||||
import requests
|
|
||||||
|
|
||||||
from glance.tests.functional.v2 import metadef_base
|
from glance.tests.functional.v2 import metadef_base
|
||||||
|
|
||||||
@@ -25,23 +24,21 @@ class TestNamespaceProperties(metadef_base.MetadefFunctionalTestBase):
|
|||||||
|
|
||||||
def setUp(self):
|
def setUp(self):
|
||||||
super(TestNamespaceProperties, self).setUp()
|
super(TestNamespaceProperties, self).setUp()
|
||||||
self.cleanup()
|
self.start_server(enable_cache=False)
|
||||||
self.api_server.deployment_flavor = 'noauth'
|
|
||||||
self.start_servers(**self.__dict__.copy())
|
|
||||||
|
|
||||||
def test_properties_lifecycle(self):
|
def test_properties_lifecycle(self):
|
||||||
# Namespace should not exist
|
# Namespace should not exist
|
||||||
path = self._url('/v2/metadefs/namespaces/MyNamespace')
|
path = '/v2/metadefs/namespaces/MyNamespace'
|
||||||
response = requests.get(path, headers=self._headers())
|
response = self.api_get(path, headers=self._headers())
|
||||||
self.assertEqual(http.NOT_FOUND, response.status_code)
|
self.assertEqual(http.NOT_FOUND, response.status_code)
|
||||||
|
|
||||||
# Create a namespace
|
# Create a namespace
|
||||||
path = self._url('/v2/metadefs/namespaces')
|
path = '/v2/metadefs/namespaces'
|
||||||
headers = self._headers({'content-type': 'application/json'})
|
headers = self._headers({'content-type': 'application/json'})
|
||||||
namespace_name = 'MyNamespace'
|
namespace_name = 'MyNamespace'
|
||||||
resource_type_name = 'MyResourceType'
|
resource_type_name = 'MyResourceType'
|
||||||
resource_type_prefix = 'MyPrefix'
|
resource_type_prefix = 'MyPrefix'
|
||||||
data = jsonutils.dumps({
|
data = {
|
||||||
"namespace": namespace_name,
|
"namespace": namespace_name,
|
||||||
"display_name": "My User Friendly Namespace",
|
"display_name": "My User Friendly Namespace",
|
||||||
"description": "My description",
|
"description": "My description",
|
||||||
@@ -54,43 +51,40 @@ class TestNamespaceProperties(metadef_base.MetadefFunctionalTestBase):
|
|||||||
"prefix": resource_type_prefix
|
"prefix": resource_type_prefix
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
})
|
}
|
||||||
response = requests.post(path, headers=headers, data=data)
|
response = self.api_post(path, headers=headers, json=data)
|
||||||
self.assertEqual(http.CREATED, response.status_code)
|
self.assertEqual(http.CREATED, response.status_code)
|
||||||
|
|
||||||
# Property1 should not exist
|
# Property1 should not exist
|
||||||
path = self._url('/v2/metadefs/namespaces/MyNamespace/properties'
|
path = '/v2/metadefs/namespaces/MyNamespace/properties/property1'
|
||||||
'/property1')
|
response = self.api_get(path, headers=self._headers())
|
||||||
response = requests.get(path, headers=self._headers())
|
|
||||||
self.assertEqual(http.NOT_FOUND, response.status_code)
|
self.assertEqual(http.NOT_FOUND, response.status_code)
|
||||||
|
|
||||||
# Create a property
|
# Create a property
|
||||||
path = self._url('/v2/metadefs/namespaces/MyNamespace/properties')
|
path = '/v2/metadefs/namespaces/MyNamespace/properties'
|
||||||
headers = self._headers({'content-type': 'application/json'})
|
headers = self._headers({'content-type': 'application/json'})
|
||||||
property_name = "property1"
|
property_name = "property1"
|
||||||
data = jsonutils.dumps(
|
data = {
|
||||||
{
|
"name": property_name,
|
||||||
"name": property_name,
|
"type": "integer",
|
||||||
"type": "integer",
|
"title": "property1",
|
||||||
"title": "property1",
|
"description": "property1 description",
|
||||||
"description": "property1 description",
|
"default": 100,
|
||||||
"default": 100,
|
"minimum": 100,
|
||||||
"minimum": 100,
|
"maximum": 30000369,
|
||||||
"maximum": 30000369,
|
"readonly": False,
|
||||||
"readonly": False,
|
}
|
||||||
}
|
response = self.api_post(path, headers=headers, json=data)
|
||||||
)
|
|
||||||
response = requests.post(path, headers=headers, data=data)
|
|
||||||
self.assertEqual(http.CREATED, response.status_code)
|
self.assertEqual(http.CREATED, response.status_code)
|
||||||
|
|
||||||
# Attempt to insert a duplicate
|
# Attempt to insert a duplicate
|
||||||
response = requests.post(path, headers=headers, data=data)
|
response = self.api_post(path, headers=headers, json=data)
|
||||||
self.assertEqual(http.CONFLICT, response.status_code)
|
self.assertEqual(http.CONFLICT, response.status_code)
|
||||||
|
|
||||||
# Get the property created above
|
# Get the property created above
|
||||||
path = self._url('/v2/metadefs/namespaces/%s/properties/%s' %
|
path = '/v2/metadefs/namespaces/%s/properties/%s' % (
|
||||||
(namespace_name, property_name))
|
namespace_name, property_name)
|
||||||
response = requests.get(path, headers=self._headers())
|
response = self.api_get(path, headers=self._headers())
|
||||||
self.assertEqual(http.OK, response.status_code)
|
self.assertEqual(http.OK, response.status_code)
|
||||||
property_object = jsonutils.loads(response.text)
|
property_object = jsonutils.loads(response.text)
|
||||||
self.assertEqual("integer", property_object['type'])
|
self.assertEqual("integer", property_object['type'])
|
||||||
@@ -102,19 +96,19 @@ class TestNamespaceProperties(metadef_base.MetadefFunctionalTestBase):
|
|||||||
self.assertEqual(30000369, property_object['maximum'])
|
self.assertEqual(30000369, property_object['maximum'])
|
||||||
|
|
||||||
# Get the property with specific resource type association
|
# Get the property with specific resource type association
|
||||||
path = self._url('/v2/metadefs/namespaces/%s/properties/%s%s' % (
|
path = '/v2/metadefs/namespaces/%s/properties/%s%s' % (
|
||||||
namespace_name, property_name, '='.join(['?resource_type',
|
namespace_name, property_name, '='.join(['?resource_type',
|
||||||
resource_type_name])))
|
resource_type_name]))
|
||||||
response = requests.get(path, headers=self._headers())
|
response = self.api_get(path, headers=self._headers())
|
||||||
self.assertEqual(http.NOT_FOUND, response.status_code)
|
self.assertEqual(http.NOT_FOUND, response.status_code)
|
||||||
|
|
||||||
# Get the property with prefix and specific resource type association
|
# Get the property with prefix and specific resource type association
|
||||||
property_name_with_prefix = ''.join([resource_type_prefix,
|
property_name_with_prefix = ''.join([resource_type_prefix,
|
||||||
property_name])
|
property_name])
|
||||||
path = self._url('/v2/metadefs/namespaces/%s/properties/%s%s' % (
|
path = '/v2/metadefs/namespaces/%s/properties/%s%s' % (
|
||||||
namespace_name, property_name_with_prefix, '='.join([
|
namespace_name, property_name_with_prefix, '='.join([
|
||||||
'?resource_type', resource_type_name])))
|
'?resource_type', resource_type_name]))
|
||||||
response = requests.get(path, headers=self._headers())
|
response = self.api_get(path, headers=self._headers())
|
||||||
self.assertEqual(http.OK, response.status_code)
|
self.assertEqual(http.OK, response.status_code)
|
||||||
property_object = jsonutils.loads(response.text)
|
property_object = jsonutils.loads(response.text)
|
||||||
self.assertEqual("integer", property_object['type'])
|
self.assertEqual("integer", property_object['type'])
|
||||||
@@ -153,25 +147,23 @@ class TestNamespaceProperties(metadef_base.MetadefFunctionalTestBase):
|
|||||||
self.assertEqual(property_object[key], value, key)
|
self.assertEqual(property_object[key], value, key)
|
||||||
|
|
||||||
# The property should be mutable
|
# The property should be mutable
|
||||||
path = self._url('/v2/metadefs/namespaces/%s/properties/%s' %
|
path = '/v2/metadefs/namespaces/%s/properties/%s' % (
|
||||||
(namespace_name, property_name))
|
namespace_name, property_name)
|
||||||
media_type = 'application/json'
|
media_type = 'application/json'
|
||||||
headers = self._headers({'content-type': media_type})
|
headers = self._headers({'content-type': media_type})
|
||||||
property_name = "property1-UPDATED"
|
property_name = "property1-UPDATED"
|
||||||
data = jsonutils.dumps(
|
data = {
|
||||||
{
|
"name": property_name,
|
||||||
"name": property_name,
|
"type": "string",
|
||||||
"type": "string",
|
"title": "string property",
|
||||||
"title": "string property",
|
"description": "desc-UPDATED",
|
||||||
"description": "desc-UPDATED",
|
"operators": ["<or>"],
|
||||||
"operators": ["<or>"],
|
"default": "value-UPDATED",
|
||||||
"default": "value-UPDATED",
|
"minLength": 5,
|
||||||
"minLength": 5,
|
"maxLength": 10,
|
||||||
"maxLength": 10,
|
"readonly": True,
|
||||||
"readonly": True,
|
}
|
||||||
}
|
response = self.api_put(path, headers=headers, json=data)
|
||||||
)
|
|
||||||
response = requests.put(path, headers=headers, data=data)
|
|
||||||
self.assertEqual(http.OK, response.status_code, response.text)
|
self.assertEqual(http.OK, response.status_code, response.text)
|
||||||
|
|
||||||
# Returned property should reflect the changes
|
# Returned property should reflect the changes
|
||||||
@@ -185,9 +177,10 @@ class TestNamespaceProperties(metadef_base.MetadefFunctionalTestBase):
|
|||||||
self.assertTrue(property_object['readonly'])
|
self.assertTrue(property_object['readonly'])
|
||||||
|
|
||||||
# Updates should persist across requests
|
# Updates should persist across requests
|
||||||
path = self._url('/v2/metadefs/namespaces/%s/properties/%s' %
|
path = '/v2/metadefs/namespaces/%s/properties/%s' % (
|
||||||
(namespace_name, property_name))
|
namespace_name, property_name)
|
||||||
response = requests.get(path, headers=self._headers())
|
response = self.api_get(path, headers=self._headers())
|
||||||
|
property_object = jsonutils.loads(response.text)
|
||||||
self.assertEqual('string', property_object['type'])
|
self.assertEqual('string', property_object['type'])
|
||||||
self.assertEqual('desc-UPDATED', property_object['description'])
|
self.assertEqual('desc-UPDATED', property_object['description'])
|
||||||
self.assertEqual('value-UPDATED', property_object['default'])
|
self.assertEqual('value-UPDATED', property_object['default'])
|
||||||
@@ -196,15 +189,15 @@ class TestNamespaceProperties(metadef_base.MetadefFunctionalTestBase):
|
|||||||
self.assertEqual(10, property_object['maxLength'])
|
self.assertEqual(10, property_object['maxLength'])
|
||||||
|
|
||||||
# Deletion of property property1
|
# Deletion of property property1
|
||||||
path = self._url('/v2/metadefs/namespaces/%s/properties/%s' %
|
path = '/v2/metadefs/namespaces/%s/properties/%s' % (
|
||||||
(namespace_name, property_name))
|
namespace_name, property_name)
|
||||||
response = requests.delete(path, headers=self._headers())
|
response = self.api_delete(path, headers=self._headers())
|
||||||
self.assertEqual(http.NO_CONTENT, response.status_code)
|
self.assertEqual(http.NO_CONTENT, response.status_code)
|
||||||
|
|
||||||
# property1 should not exist
|
# property1 should not exist
|
||||||
path = self._url('/v2/metadefs/namespaces/%s/properties/%s' %
|
path = '/v2/metadefs/namespaces/%s/properties/%s' % (
|
||||||
(namespace_name, property_name))
|
namespace_name, property_name)
|
||||||
response = requests.get(path, headers=self._headers())
|
response = self.api_get(path, headers=self._headers())
|
||||||
self.assertEqual(http.NOT_FOUND, response.status_code)
|
self.assertEqual(http.NOT_FOUND, response.status_code)
|
||||||
|
|
||||||
def _create_properties(self, namespaces):
|
def _create_properties(self, namespaces):
|
||||||
@@ -217,11 +210,11 @@ class TestNamespaceProperties(metadef_base.MetadefFunctionalTestBase):
|
|||||||
"title": "property",
|
"title": "property",
|
||||||
"description": "property description",
|
"description": "property description",
|
||||||
}
|
}
|
||||||
path = self._url('/v2/metadefs/namespaces/%s/properties' %
|
path = ('/v2/metadefs/namespaces/%s/'
|
||||||
namespace['namespace'])
|
'properties') % namespace['namespace']
|
||||||
response = requests.post(path, headers=headers, json=data)
|
response = self.api_post(path, headers=headers, json=data)
|
||||||
self.assertEqual(http.CREATED, response.status_code)
|
self.assertEqual(http.CREATED, response.status_code)
|
||||||
prop_metadata = response.json()
|
prop_metadata = jsonutils.loads(response.text)
|
||||||
metadef_property = dict()
|
metadef_property = dict()
|
||||||
metadef_property[namespace['namespace']] = prop_metadata['name']
|
metadef_property[namespace['namespace']] = prop_metadata['name']
|
||||||
properties.append(metadef_property)
|
properties.append(metadef_property)
|
||||||
@@ -230,22 +223,23 @@ class TestNamespaceProperties(metadef_base.MetadefFunctionalTestBase):
|
|||||||
|
|
||||||
def _update_property(self, path, headers, data):
|
def _update_property(self, path, headers, data):
|
||||||
# The property should be mutable
|
# The property should be mutable
|
||||||
response = requests.put(path, headers=headers, json=data)
|
response = self.api_put(path, headers=headers, json=data)
|
||||||
self.assertEqual(http.OK, response.status_code, response.text)
|
self.assertEqual(http.OK, response.status_code, response.text)
|
||||||
|
|
||||||
# Returned property should reflect the changes
|
# Returned property should reflect the changes
|
||||||
property_object = response.json()
|
property_object = jsonutils.loads(response.text)
|
||||||
self.assertEqual('string', property_object['type'])
|
self.assertEqual('string', property_object['type'])
|
||||||
self.assertEqual(data['description'], property_object['description'])
|
self.assertEqual(data['description'], property_object['description'])
|
||||||
|
|
||||||
# Updates should persist across requests
|
# Updates should persist across requests
|
||||||
response = requests.get(path, headers=self._headers())
|
response = self.api_get(path, headers=self._headers())
|
||||||
|
property_object = jsonutils.loads(response.text)
|
||||||
self.assertEqual('string', property_object['type'])
|
self.assertEqual('string', property_object['type'])
|
||||||
self.assertEqual(data['description'], property_object['description'])
|
self.assertEqual(data['description'], property_object['description'])
|
||||||
|
|
||||||
def test_role_base_metadata_properties_lifecycle(self):
|
def test_role_base_metadata_properties_lifecycle(self):
|
||||||
# Create public and private namespaces for tenant1 and tenant2
|
# Create public and private namespaces for tenant1 and tenant2
|
||||||
path = self._url('/v2/metadefs/namespaces')
|
path = '/v2/metadefs/namespaces'
|
||||||
headers = self._headers({'content-type': 'application/json'})
|
headers = self._headers({'content-type': 'application/json'})
|
||||||
tenant1_namespaces = []
|
tenant1_namespaces = []
|
||||||
tenant2_namespaces = []
|
tenant2_namespaces = []
|
||||||
@@ -261,6 +255,7 @@ class TestNamespaceProperties(metadef_base.MetadefFunctionalTestBase):
|
|||||||
}
|
}
|
||||||
namespace = self.create_namespace(path, headers,
|
namespace = self.create_namespace(path, headers,
|
||||||
namespace_data)
|
namespace_data)
|
||||||
|
namespace = jsonutils.loads(namespace.text)
|
||||||
self.assertNamespacesEqual(namespace, namespace_data)
|
self.assertNamespacesEqual(namespace, namespace_data)
|
||||||
if tenant == self.tenant1:
|
if tenant == self.tenant1:
|
||||||
tenant1_namespaces.append(namespace)
|
tenant1_namespaces.append(namespace)
|
||||||
@@ -277,10 +272,9 @@ class TestNamespaceProperties(metadef_base.MetadefFunctionalTestBase):
|
|||||||
'X-Roles': 'reader,member'})
|
'X-Roles': 'reader,member'})
|
||||||
for prop in properties:
|
for prop in properties:
|
||||||
for namespace, property_name in prop.items():
|
for namespace, property_name in prop.items():
|
||||||
path = \
|
path = '/v2/metadefs/namespaces/%s/properties/%s' % (
|
||||||
self._url('/v2/metadefs/namespaces/%s/properties/%s' %
|
namespace, property_name)
|
||||||
(namespace, property_name))
|
response = self.api_get(path, headers=headers)
|
||||||
response = requests.get(path, headers=headers)
|
|
||||||
if namespace.split('_')[1] == 'public':
|
if namespace.split('_')[1] == 'public':
|
||||||
expected = http.OK
|
expected = http.OK
|
||||||
else:
|
else:
|
||||||
@@ -291,12 +285,12 @@ class TestNamespaceProperties(metadef_base.MetadefFunctionalTestBase):
|
|||||||
self.assertEqual(expected, response.status_code)
|
self.assertEqual(expected, response.status_code)
|
||||||
|
|
||||||
# Make sure the same holds for listing
|
# Make sure the same holds for listing
|
||||||
path = self._url(
|
path = '/v2/metadefs/namespaces/%s/properties' % namespace
|
||||||
'/v2/metadefs/namespaces/%s/properties' % namespace)
|
response = self.api_get(path, headers=headers)
|
||||||
response = requests.get(path, headers=headers)
|
|
||||||
self.assertEqual(expected, response.status_code)
|
self.assertEqual(expected, response.status_code)
|
||||||
if expected == http.OK:
|
if expected == http.OK:
|
||||||
resp_props = response.json()['properties'].values()
|
resp_props = jsonutils.loads(
|
||||||
|
response.text)['properties'].values()
|
||||||
self.assertEqual(
|
self.assertEqual(
|
||||||
sorted(prop.values()),
|
sorted(prop.values()),
|
||||||
sorted([x['name']
|
sorted([x['name']
|
||||||
@@ -320,12 +314,12 @@ class TestNamespaceProperties(metadef_base.MetadefFunctionalTestBase):
|
|||||||
"title": "string property",
|
"title": "string property",
|
||||||
"description": "desc-UPDATED",
|
"description": "desc-UPDATED",
|
||||||
}
|
}
|
||||||
path = self._url('/v2/metadefs/namespaces/%s/properties/%s' %
|
path = '/v2/metadefs/namespaces/%s/properties/%s' % (
|
||||||
(namespace, property_name))
|
namespace, property_name)
|
||||||
|
|
||||||
# Update property should fail with non admin role
|
# Update property should fail with non admin role
|
||||||
headers['X-Roles'] = "reader,member"
|
headers['X-Roles'] = "reader,member"
|
||||||
response = requests.put(path, headers=headers, json=data)
|
response = self.api_put(path, headers=headers, json=data)
|
||||||
self.assertEqual(http.FORBIDDEN, response.status_code)
|
self.assertEqual(http.FORBIDDEN, response.status_code)
|
||||||
|
|
||||||
# Should work with admin role
|
# Should work with admin role
|
||||||
@@ -336,9 +330,9 @@ class TestNamespaceProperties(metadef_base.MetadefFunctionalTestBase):
|
|||||||
# Delete property should not be allowed to non admin role
|
# Delete property should not be allowed to non admin role
|
||||||
for prop in total_properties:
|
for prop in total_properties:
|
||||||
for namespace, property_name in prop.items():
|
for namespace, property_name in prop.items():
|
||||||
path = self._url('/v2/metadefs/namespaces/%s/properties/%s' %
|
path = '/v2/metadefs/namespaces/%s/properties/%s' % (
|
||||||
(namespace, property_name))
|
namespace, property_name)
|
||||||
response = requests.delete(
|
response = self.api_delete(
|
||||||
path, headers=self._headers({
|
path, headers=self._headers({
|
||||||
'X-Roles': 'reader,member',
|
'X-Roles': 'reader,member',
|
||||||
'X-Tenant-Id': namespace.split('_')[0]
|
'X-Tenant-Id': namespace.split('_')[0]
|
||||||
@@ -349,11 +343,11 @@ class TestNamespaceProperties(metadef_base.MetadefFunctionalTestBase):
|
|||||||
headers = self._headers()
|
headers = self._headers()
|
||||||
for prop in total_properties:
|
for prop in total_properties:
|
||||||
for namespace, property_name in prop.items():
|
for namespace, property_name in prop.items():
|
||||||
path = self._url('/v2/metadefs/namespaces/%s/properties/%s' %
|
path = '/v2/metadefs/namespaces/%s/properties/%s' % (
|
||||||
(namespace, property_name))
|
namespace, property_name)
|
||||||
response = requests.delete(path, headers=headers)
|
response = self.api_delete(path, headers=headers)
|
||||||
self.assertEqual(http.NO_CONTENT, response.status_code)
|
self.assertEqual(http.NO_CONTENT, response.status_code)
|
||||||
|
|
||||||
# Deleted property should not be exist
|
# Deleted property should not exist
|
||||||
response = requests.get(path, headers=headers)
|
response = self.api_get(path, headers=headers)
|
||||||
self.assertEqual(http.NOT_FOUND, response.status_code)
|
self.assertEqual(http.NOT_FOUND, response.status_code)
|
||||||
|
@@ -16,7 +16,6 @@
|
|||||||
import http.client as http
|
import http.client as http
|
||||||
|
|
||||||
from oslo_serialization import jsonutils
|
from oslo_serialization import jsonutils
|
||||||
import requests
|
|
||||||
|
|
||||||
from glance.tests.functional.v2 import metadef_base
|
from glance.tests.functional.v2 import metadef_base
|
||||||
|
|
||||||
@@ -25,61 +24,55 @@ class TestMetadefResourceTypes(metadef_base.MetadefFunctionalTestBase):
|
|||||||
|
|
||||||
def setUp(self):
|
def setUp(self):
|
||||||
super(TestMetadefResourceTypes, self).setUp()
|
super(TestMetadefResourceTypes, self).setUp()
|
||||||
self.cleanup()
|
self.start_server(enable_cache=False)
|
||||||
self.api_server.deployment_flavor = 'noauth'
|
|
||||||
self.start_servers(**self.__dict__.copy())
|
|
||||||
|
|
||||||
def test_metadef_resource_types_lifecycle(self):
|
def test_metadef_resource_types_lifecycle(self):
|
||||||
# Namespace should not exist
|
# Namespace should not exist
|
||||||
path = self._url('/v2/metadefs/namespaces/MyNamespace')
|
path = '/v2/metadefs/namespaces/MyNamespace'
|
||||||
response = requests.get(path, headers=self._headers())
|
response = self.api_get(path, headers=self._headers())
|
||||||
self.assertEqual(http.NOT_FOUND, response.status_code)
|
self.assertEqual(http.NOT_FOUND, response.status_code)
|
||||||
|
|
||||||
# Create a namespace
|
# Create a namespace
|
||||||
path = self._url('/v2/metadefs/namespaces')
|
path = '/v2/metadefs/namespaces'
|
||||||
headers = self._headers({'content-type': 'application/json'})
|
headers = self._headers({'content-type': 'application/json'})
|
||||||
namespace_name = 'MyNamespace'
|
namespace_name = 'MyNamespace'
|
||||||
data = jsonutils.dumps({
|
data = {
|
||||||
"namespace": namespace_name,
|
"namespace": namespace_name,
|
||||||
"display_name": "My User Friendly Namespace",
|
"display_name": "My User Friendly Namespace",
|
||||||
"description": "My description",
|
"description": "My description",
|
||||||
"visibility": "public",
|
"visibility": "public",
|
||||||
"protected": False,
|
"protected": False,
|
||||||
"owner": "The Test Owner"
|
"owner": "The Test Owner"
|
||||||
})
|
}
|
||||||
response = requests.post(path, headers=headers, data=data)
|
response = self.api_post(path, headers=headers, json=data)
|
||||||
self.assertEqual(http.CREATED, response.status_code)
|
self.assertEqual(http.CREATED, response.status_code)
|
||||||
|
|
||||||
# Resource type should not exist
|
# Resource type should not exist
|
||||||
path = self._url('/v2/metadefs/namespaces/%s/resource_types' %
|
path = '/v2/metadefs/namespaces/%s/resource_types' % (namespace_name)
|
||||||
(namespace_name))
|
response = self.api_get(path, headers=self._headers())
|
||||||
response = requests.get(path, headers=self._headers())
|
|
||||||
metadef_resource_type = jsonutils.loads(response.text)
|
metadef_resource_type = jsonutils.loads(response.text)
|
||||||
self.assertEqual(
|
self.assertEqual(
|
||||||
0, len(metadef_resource_type['resource_type_associations']))
|
0, len(metadef_resource_type['resource_type_associations']))
|
||||||
|
|
||||||
# Create a resource type
|
# Create a resource type
|
||||||
path = self._url('/v2/metadefs/namespaces/MyNamespace/resource_types')
|
path = '/v2/metadefs/namespaces/MyNamespace/resource_types'
|
||||||
headers = self._headers({'content-type': 'application/json'})
|
headers = self._headers({'content-type': 'application/json'})
|
||||||
metadef_resource_type_name = "resource_type1"
|
metadef_resource_type_name = "resource_type1"
|
||||||
data = jsonutils.dumps(
|
data = {
|
||||||
{
|
"name": "resource_type1",
|
||||||
"name": "resource_type1",
|
"prefix": "hw_",
|
||||||
"prefix": "hw_",
|
"properties_target": "image",
|
||||||
"properties_target": "image",
|
}
|
||||||
}
|
response = self.api_post(path, headers=headers, json=data)
|
||||||
)
|
|
||||||
response = requests.post(path, headers=headers, data=data)
|
|
||||||
self.assertEqual(http.CREATED, response.status_code)
|
self.assertEqual(http.CREATED, response.status_code)
|
||||||
|
|
||||||
# Attempt to insert a duplicate
|
# Attempt to insert a duplicate
|
||||||
response = requests.post(path, headers=headers, data=data)
|
response = self.api_post(path, headers=headers, json=data)
|
||||||
self.assertEqual(http.CONFLICT, response.status_code)
|
self.assertEqual(http.CONFLICT, response.status_code)
|
||||||
|
|
||||||
# Get the metadef resource type created above
|
# Get the metadef resource type created above
|
||||||
path = self._url('/v2/metadefs/namespaces/%s/resource_types' %
|
path = '/v2/metadefs/namespaces/%s/resource_types' % (namespace_name)
|
||||||
(namespace_name))
|
response = self.api_get(path,
|
||||||
response = requests.get(path,
|
|
||||||
headers=self._headers())
|
headers=self._headers())
|
||||||
self.assertEqual(http.OK, response.status_code)
|
self.assertEqual(http.OK, response.status_code)
|
||||||
metadef_resource_type = jsonutils.loads(response.text)
|
metadef_resource_type = jsonutils.loads(response.text)
|
||||||
@@ -118,15 +111,14 @@ class TestMetadefResourceTypes(metadef_base.MetadefFunctionalTestBase):
|
|||||||
value, key)
|
value, key)
|
||||||
|
|
||||||
# Deassociate of metadef resource type resource_type1
|
# Deassociate of metadef resource type resource_type1
|
||||||
path = self._url('/v2/metadefs/namespaces/%s/resource_types/%s' %
|
path = '/v2/metadefs/namespaces/%s/resource_types/%s' % (
|
||||||
(namespace_name, metadef_resource_type_name))
|
namespace_name, metadef_resource_type_name)
|
||||||
response = requests.delete(path, headers=self._headers())
|
response = self.api_delete(path, headers=self._headers())
|
||||||
self.assertEqual(http.NO_CONTENT, response.status_code)
|
self.assertEqual(http.NO_CONTENT, response.status_code)
|
||||||
|
|
||||||
# resource_type1 should not exist
|
# resource_type1 should not exist
|
||||||
path = self._url('/v2/metadefs/namespaces/%s/resource_types' %
|
path = '/v2/metadefs/namespaces/%s/resource_types' % (namespace_name)
|
||||||
(namespace_name))
|
response = self.api_get(path, headers=self._headers())
|
||||||
response = requests.get(path, headers=self._headers())
|
|
||||||
metadef_resource_type = jsonutils.loads(response.text)
|
metadef_resource_type = jsonutils.loads(response.text)
|
||||||
self.assertEqual(
|
self.assertEqual(
|
||||||
0, len(metadef_resource_type['resource_type_associations']))
|
0, len(metadef_resource_type['resource_type_associations']))
|
||||||
@@ -140,11 +132,11 @@ class TestMetadefResourceTypes(metadef_base.MetadefFunctionalTestBase):
|
|||||||
"prefix": "hw_",
|
"prefix": "hw_",
|
||||||
"properties_target": "image"
|
"properties_target": "image"
|
||||||
}
|
}
|
||||||
path = self._url('/v2/metadefs/namespaces/%s/resource_types' %
|
path = ('/v2/metadefs/namespaces/%s/'
|
||||||
(namespace['namespace']))
|
'resource_types') % (namespace['namespace'])
|
||||||
response = requests.post(path, headers=headers, json=data)
|
response = self.api_post(path, headers=headers, json=data)
|
||||||
self.assertEqual(http.CREATED, response.status_code)
|
self.assertEqual(http.CREATED, response.status_code)
|
||||||
rs_type = response.json()
|
rs_type = jsonutils.loads(response.text)
|
||||||
resource_type = dict()
|
resource_type = dict()
|
||||||
resource_type[namespace['namespace']] = rs_type['name']
|
resource_type[namespace['namespace']] = rs_type['name']
|
||||||
resource_types.append(resource_type)
|
resource_types.append(resource_type)
|
||||||
@@ -153,7 +145,7 @@ class TestMetadefResourceTypes(metadef_base.MetadefFunctionalTestBase):
|
|||||||
|
|
||||||
def test_role_base_metadef_resource_types_lifecycle(self):
|
def test_role_base_metadef_resource_types_lifecycle(self):
|
||||||
# Create public and private namespaces for tenant1 and tenant2
|
# Create public and private namespaces for tenant1 and tenant2
|
||||||
path = self._url('/v2/metadefs/namespaces')
|
path = '/v2/metadefs/namespaces'
|
||||||
headers = self._headers({'content-type': 'application/json'})
|
headers = self._headers({'content-type': 'application/json'})
|
||||||
tenant1_namespaces = []
|
tenant1_namespaces = []
|
||||||
tenant2_namespaces = []
|
tenant2_namespaces = []
|
||||||
@@ -169,6 +161,7 @@ class TestMetadefResourceTypes(metadef_base.MetadefFunctionalTestBase):
|
|||||||
}
|
}
|
||||||
namespace = self.create_namespace(path, headers,
|
namespace = self.create_namespace(path, headers,
|
||||||
namespace_data)
|
namespace_data)
|
||||||
|
namespace = jsonutils.loads(namespace.text)
|
||||||
self.assertNamespacesEqual(namespace, namespace_data)
|
self.assertNamespacesEqual(namespace, namespace_data)
|
||||||
if tenant == self.tenant1:
|
if tenant == self.tenant1:
|
||||||
tenant1_namespaces.append(namespace)
|
tenant1_namespaces.append(namespace)
|
||||||
@@ -185,9 +178,9 @@ class TestMetadefResourceTypes(metadef_base.MetadefFunctionalTestBase):
|
|||||||
headers = self._headers({'X-Tenant-Id': tenant,
|
headers = self._headers({'X-Tenant-Id': tenant,
|
||||||
'X-Roles': 'reader,member'})
|
'X-Roles': 'reader,member'})
|
||||||
for namespace in namespaces:
|
for namespace in namespaces:
|
||||||
path = self._url('/v2/metadefs/namespaces/%s/resource_types' %
|
path = ('/v2/metadefs/namespaces/%s/'
|
||||||
(namespace['namespace']))
|
'resource_types') % (namespace['namespace'])
|
||||||
response = requests.get(path, headers=headers)
|
response = self.api_get(path, headers=headers)
|
||||||
if namespace['visibility'] == 'public':
|
if namespace['visibility'] == 'public':
|
||||||
self.assertEqual(http.OK, response.status_code)
|
self.assertEqual(http.OK, response.status_code)
|
||||||
else:
|
else:
|
||||||
@@ -195,12 +188,12 @@ class TestMetadefResourceTypes(metadef_base.MetadefFunctionalTestBase):
|
|||||||
|
|
||||||
def _check_resource_types(tenant, total_rs_types):
|
def _check_resource_types(tenant, total_rs_types):
|
||||||
# Resource types are visible across tenants for all users
|
# Resource types are visible across tenants for all users
|
||||||
path = self._url('/v2/metadefs/resource_types')
|
path = '/v2/metadefs/resource_types'
|
||||||
headers = self._headers({'X-Tenant-Id': tenant,
|
headers = self._headers({'X-Tenant-Id': tenant,
|
||||||
'X-Roles': 'reader,member'})
|
'X-Roles': 'reader,member'})
|
||||||
response = requests.get(path, headers=headers)
|
response = self.api_get(path, headers=headers)
|
||||||
self.assertEqual(http.OK, response.status_code)
|
self.assertEqual(http.OK, response.status_code)
|
||||||
metadef_resource_type = response.json()
|
metadef_resource_type = jsonutils.loads(response.text)
|
||||||
|
|
||||||
# The resource types list count should be same as the total
|
# The resource types list count should be same as the total
|
||||||
# resource types created across the tenants.
|
# resource types created across the tenants.
|
||||||
@@ -227,10 +220,9 @@ class TestMetadefResourceTypes(metadef_base.MetadefFunctionalTestBase):
|
|||||||
# Disassociate resource type should not be allowed to non admin role
|
# Disassociate resource type should not be allowed to non admin role
|
||||||
for resource_type in total_resource_types:
|
for resource_type in total_resource_types:
|
||||||
for namespace, rs_type in resource_type.items():
|
for namespace, rs_type in resource_type.items():
|
||||||
path = \
|
path = '/v2/metadefs/namespaces/%s/resource_types/%s' % (
|
||||||
self._url('/v2/metadefs/namespaces/%s/resource_types/%s' %
|
namespace, rs_type)
|
||||||
(namespace, rs_type))
|
response = self.api_delete(
|
||||||
response = requests.delete(
|
|
||||||
path, headers=self._headers({
|
path, headers=self._headers({
|
||||||
'X-Roles': 'reader,member',
|
'X-Roles': 'reader,member',
|
||||||
'X-Tenant-Id': namespace.split('_')[0]
|
'X-Tenant-Id': namespace.split('_')[0]
|
||||||
@@ -241,19 +233,17 @@ class TestMetadefResourceTypes(metadef_base.MetadefFunctionalTestBase):
|
|||||||
headers = self._headers()
|
headers = self._headers()
|
||||||
for resource_type in total_resource_types:
|
for resource_type in total_resource_types:
|
||||||
for namespace, rs_type in resource_type.items():
|
for namespace, rs_type in resource_type.items():
|
||||||
path = \
|
path = '/v2/metadefs/namespaces/%s/resource_types/%s' % (
|
||||||
self._url('/v2/metadefs/namespaces/%s/resource_types/%s' %
|
namespace, rs_type)
|
||||||
(namespace, rs_type))
|
response = self.api_delete(path, headers=headers)
|
||||||
response = requests.delete(path, headers=headers)
|
|
||||||
self.assertEqual(http.NO_CONTENT, response.status_code)
|
self.assertEqual(http.NO_CONTENT, response.status_code)
|
||||||
|
|
||||||
# Disassociated resource type should not be exist
|
# Disassociated resource type should not be exist
|
||||||
# When the specified resource type is not associated with given
|
# When the specified resource type is not associated with given
|
||||||
# namespace then it returns empty list in response instead of
|
# namespace then it returns empty list in response instead of
|
||||||
# raising not found error
|
# raising not found error
|
||||||
path = self._url(
|
path = '/v2/metadefs/namespaces/%s/resource_types' % namespace
|
||||||
'/v2/metadefs/namespaces/%s/resource_types' % namespace)
|
response = self.api_get(path, headers=headers)
|
||||||
response = requests.get(path, headers=headers)
|
metadef_resource_type = jsonutils.loads(response.text)
|
||||||
metadef_resource_type = response.json()
|
|
||||||
self.assertEqual(
|
self.assertEqual(
|
||||||
[], metadef_resource_type['resource_type_associations'])
|
[], metadef_resource_type['resource_type_associations'])
|
||||||
|
@@ -16,7 +16,6 @@
|
|||||||
import http.client as http
|
import http.client as http
|
||||||
|
|
||||||
from oslo_serialization import jsonutils
|
from oslo_serialization import jsonutils
|
||||||
import requests
|
|
||||||
|
|
||||||
from glance.tests.functional.v2 import metadef_base
|
from glance.tests.functional.v2 import metadef_base
|
||||||
|
|
||||||
@@ -25,52 +24,49 @@ class TestMetadefTags(metadef_base.MetadefFunctionalTestBase):
|
|||||||
|
|
||||||
def setUp(self):
|
def setUp(self):
|
||||||
super(TestMetadefTags, self).setUp()
|
super(TestMetadefTags, self).setUp()
|
||||||
self.cleanup()
|
self.start_server(enable_cache=False)
|
||||||
self.api_server.deployment_flavor = 'noauth'
|
|
||||||
self.start_servers(**self.__dict__.copy())
|
|
||||||
|
|
||||||
def test_metadata_tags_lifecycle(self):
|
def test_metadata_tags_lifecycle(self):
|
||||||
# Namespace should not exist
|
# Namespace should not exist
|
||||||
path = self._url('/v2/metadefs/namespaces/MyNamespace')
|
path = '/v2/metadefs/namespaces/MyNamespace'
|
||||||
response = requests.get(path, headers=self._headers())
|
response = self.api_get(path, headers=self._headers())
|
||||||
self.assertEqual(http.NOT_FOUND, response.status_code)
|
self.assertEqual(http.NOT_FOUND, response.status_code)
|
||||||
|
|
||||||
# Create a namespace
|
# Create a namespace
|
||||||
path = self._url('/v2/metadefs/namespaces')
|
path = '/v2/metadefs/namespaces'
|
||||||
headers = self._headers({'content-type': 'application/json'})
|
headers = self._headers({'content-type': 'application/json'})
|
||||||
namespace_name = 'MyNamespace'
|
namespace_name = 'MyNamespace'
|
||||||
data = jsonutils.dumps({
|
data = {
|
||||||
"namespace": namespace_name,
|
"namespace": namespace_name,
|
||||||
"display_name": "My User Friendly Namespace",
|
"display_name": "My User Friendly Namespace",
|
||||||
"description": "My description",
|
"description": "My description",
|
||||||
"visibility": "public",
|
"visibility": "public",
|
||||||
"protected": False,
|
"protected": False,
|
||||||
"owner": "The Test Owner"}
|
"owner": "The Test Owner"
|
||||||
)
|
}
|
||||||
response = requests.post(path, headers=headers, data=data)
|
response = self.api_post(path, headers=headers, json=data)
|
||||||
self.assertEqual(http.CREATED, response.status_code)
|
self.assertEqual(http.CREATED, response.status_code)
|
||||||
|
|
||||||
# Metadata tag should not exist
|
# Metadata tag should not exist
|
||||||
metadata_tag_name = "tag1"
|
metadata_tag_name = "tag1"
|
||||||
path = self._url('/v2/metadefs/namespaces/%s/tags/%s' %
|
path = '/v2/metadefs/namespaces/%s/tags/%s' % (
|
||||||
(namespace_name, metadata_tag_name))
|
namespace_name, metadata_tag_name)
|
||||||
response = requests.get(path, headers=self._headers())
|
response = self.api_get(path, headers=self._headers())
|
||||||
self.assertEqual(http.NOT_FOUND, response.status_code)
|
self.assertEqual(http.NOT_FOUND, response.status_code)
|
||||||
|
|
||||||
# Create the metadata tag
|
# Create the metadata tag
|
||||||
headers = self._headers({'content-type': 'application/json'})
|
headers = self._headers({'content-type': 'application/json'})
|
||||||
response = requests.post(path, headers=headers)
|
response = self.api_post(path, headers=headers)
|
||||||
self.assertEqual(http.CREATED, response.status_code)
|
self.assertEqual(http.CREATED, response.status_code)
|
||||||
|
|
||||||
# Get the metadata tag created above
|
# Get the metadata tag created above
|
||||||
response = requests.get(path,
|
response = self.api_get(path,
|
||||||
headers=self._headers())
|
headers=self._headers())
|
||||||
self.assertEqual(http.OK, response.status_code)
|
self.assertEqual(http.OK, response.status_code)
|
||||||
metadata_tag = jsonutils.loads(response.text)
|
metadata_tag = jsonutils.loads(response.text)
|
||||||
self.assertEqual(metadata_tag_name, metadata_tag['name'])
|
self.assertEqual(metadata_tag_name, metadata_tag['name'])
|
||||||
|
|
||||||
# Returned tag should match the created tag
|
# Returned tag should match the created tag
|
||||||
metadata_tag = jsonutils.loads(response.text)
|
|
||||||
checked_keys = set([
|
checked_keys = set([
|
||||||
'name',
|
'name',
|
||||||
'created_at',
|
'created_at',
|
||||||
@@ -91,21 +87,19 @@ class TestMetadefTags(metadef_base.MetadefFunctionalTestBase):
|
|||||||
|
|
||||||
# Try to create a duplicate metadata tag
|
# Try to create a duplicate metadata tag
|
||||||
headers = self._headers({'content-type': 'application/json'})
|
headers = self._headers({'content-type': 'application/json'})
|
||||||
response = requests.post(path, headers=headers)
|
response = self.api_post(path, headers=headers)
|
||||||
self.assertEqual(http.CONFLICT, response.status_code)
|
self.assertEqual(http.CONFLICT, response.status_code)
|
||||||
|
|
||||||
# The metadata_tag should be mutable
|
# The metadata_tag should be mutable
|
||||||
path = self._url('/v2/metadefs/namespaces/%s/tags/%s' %
|
path = '/v2/metadefs/namespaces/%s/tags/%s' % (
|
||||||
(namespace_name, metadata_tag_name))
|
namespace_name, metadata_tag_name)
|
||||||
media_type = 'application/json'
|
media_type = 'application/json'
|
||||||
headers = self._headers({'content-type': media_type})
|
headers = self._headers({'content-type': media_type})
|
||||||
metadata_tag_name = "tag1-UPDATED"
|
metadata_tag_name = "tag1-UPDATED"
|
||||||
data = jsonutils.dumps(
|
data = {
|
||||||
{
|
"name": metadata_tag_name
|
||||||
"name": metadata_tag_name
|
}
|
||||||
}
|
response = self.api_put(path, headers=headers, json=data)
|
||||||
)
|
|
||||||
response = requests.put(path, headers=headers, data=data)
|
|
||||||
self.assertEqual(http.OK, response.status_code, response.text)
|
self.assertEqual(http.OK, response.status_code, response.text)
|
||||||
|
|
||||||
# Returned metadata_tag should reflect the changes
|
# Returned metadata_tag should reflect the changes
|
||||||
@@ -113,79 +107,93 @@ class TestMetadefTags(metadef_base.MetadefFunctionalTestBase):
|
|||||||
self.assertEqual('tag1-UPDATED', metadata_tag['name'])
|
self.assertEqual('tag1-UPDATED', metadata_tag['name'])
|
||||||
|
|
||||||
# Updates should persist across requests
|
# Updates should persist across requests
|
||||||
path = self._url('/v2/metadefs/namespaces/%s/tags/%s' %
|
path = '/v2/metadefs/namespaces/%s/tags/%s' % (
|
||||||
(namespace_name, metadata_tag_name))
|
namespace_name, metadata_tag_name)
|
||||||
response = requests.get(path, headers=self._headers())
|
response = self.api_get(path, headers=self._headers())
|
||||||
self.assertEqual(http.OK, response.status_code)
|
self.assertEqual(http.OK, response.status_code)
|
||||||
self.assertEqual('tag1-UPDATED', metadata_tag['name'])
|
self.assertEqual('tag1-UPDATED', metadata_tag['name'])
|
||||||
|
|
||||||
# Deletion of metadata_tag_name
|
# Deletion of metadata_tag_name
|
||||||
path = self._url('/v2/metadefs/namespaces/%s/tags/%s' %
|
path = '/v2/metadefs/namespaces/%s/tags/%s' % (
|
||||||
(namespace_name, metadata_tag_name))
|
namespace_name, metadata_tag_name)
|
||||||
response = requests.delete(path, headers=self._headers())
|
response = self.api_delete(path, headers=self._headers())
|
||||||
self.assertEqual(http.NO_CONTENT, response.status_code)
|
self.assertEqual(http.NO_CONTENT, response.status_code)
|
||||||
|
|
||||||
# metadata_tag_name should not exist
|
# metadata_tag_name should not exist
|
||||||
path = self._url('/v2/metadefs/namespaces/%s/tags/%s' %
|
path = '/v2/metadefs/namespaces/%s/tags/%s' % (
|
||||||
(namespace_name, metadata_tag_name))
|
namespace_name, metadata_tag_name)
|
||||||
response = requests.get(path, headers=self._headers())
|
response = self.api_get(path, headers=self._headers())
|
||||||
self.assertEqual(http.NOT_FOUND, response.status_code)
|
self.assertEqual(http.NOT_FOUND, response.status_code)
|
||||||
|
|
||||||
# Create multiple tags.
|
# Create multiple tags.
|
||||||
path = self._url('/v2/metadefs/namespaces/%s/tags' %
|
path = '/v2/metadefs/namespaces/%s/tags' % namespace_name
|
||||||
(namespace_name))
|
|
||||||
headers = self._headers({'content-type': 'application/json'})
|
headers = self._headers({'content-type': 'application/json'})
|
||||||
data = jsonutils.dumps(
|
data = {
|
||||||
{"tags": [{"name": "tag1"}, {"name": "tag2"}, {"name": "tag3"}]}
|
"tags": [
|
||||||
)
|
{"name": "tag1"},
|
||||||
response = requests.post(path, headers=headers, data=data)
|
{"name": "tag2"},
|
||||||
|
{"name": "tag3"}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
response = self.api_post(path, headers=headers, json=data)
|
||||||
self.assertEqual(http.CREATED, response.status_code)
|
self.assertEqual(http.CREATED, response.status_code)
|
||||||
|
|
||||||
# List out the three new tags.
|
# List out the three new tags.
|
||||||
response = requests.get(path, headers=self._headers())
|
response = self.api_get(path, headers=self._headers())
|
||||||
self.assertEqual(http.OK, response.status_code)
|
self.assertEqual(http.OK, response.status_code)
|
||||||
tags = jsonutils.loads(response.text)['tags']
|
tags = jsonutils.loads(response.text)['tags']
|
||||||
self.assertEqual(3, len(tags))
|
self.assertEqual(3, len(tags))
|
||||||
|
|
||||||
# Attempt to create bogus duplicate tag4
|
# Attempt to create bogus duplicate tag4
|
||||||
data = jsonutils.dumps(
|
data = {
|
||||||
{"tags": [{"name": "tag4"}, {"name": "tag5"}, {"name": "tag4"}]}
|
"tags": [
|
||||||
)
|
{"name": "tag4"},
|
||||||
response = requests.post(path, headers=headers, data=data)
|
{"name": "tag5"},
|
||||||
|
{"name": "tag4"}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
response = self.api_post(path, headers=headers, json=data)
|
||||||
self.assertEqual(http.CONFLICT, response.status_code)
|
self.assertEqual(http.CONFLICT, response.status_code)
|
||||||
|
|
||||||
# Verify the previous 3 still exist
|
# Verify the previous 3 still exist
|
||||||
response = requests.get(path, headers=self._headers())
|
response = self.api_get(path, headers=self._headers())
|
||||||
self.assertEqual(http.OK, response.status_code)
|
self.assertEqual(http.OK, response.status_code)
|
||||||
tags = jsonutils.loads(response.text)['tags']
|
tags = jsonutils.loads(response.text)['tags']
|
||||||
self.assertEqual(3, len(tags))
|
self.assertEqual(3, len(tags))
|
||||||
|
|
||||||
# Create new tags and append to existing tags.
|
# Create new tags and append to existing tags.
|
||||||
path = self._url('/v2/metadefs/namespaces/%s/tags' %
|
path = '/v2/metadefs/namespaces/%s/tags' % namespace_name
|
||||||
(namespace_name))
|
|
||||||
headers = self._headers({'content-type': 'application/json',
|
headers = self._headers({'content-type': 'application/json',
|
||||||
'X-Openstack-Append': 'True'})
|
'X-Openstack-Append': 'True'})
|
||||||
data = jsonutils.dumps(
|
data = {
|
||||||
{"tags": [{"name": "tag4"}, {"name": "tag5"}, {"name": "tag6"}]}
|
"tags": [
|
||||||
)
|
{"name": "tag4"},
|
||||||
response = requests.post(path, headers=headers, data=data)
|
{"name": "tag5"},
|
||||||
|
{"name": "tag6"}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
response = self.api_post(path, headers=headers, json=data)
|
||||||
self.assertEqual(http.CREATED, response.status_code)
|
self.assertEqual(http.CREATED, response.status_code)
|
||||||
|
|
||||||
# List out all six tags.
|
# List out all six tags.
|
||||||
response = requests.get(path, headers=self._headers())
|
response = self.api_get(path, headers=self._headers())
|
||||||
self.assertEqual(http.OK, response.status_code)
|
self.assertEqual(http.OK, response.status_code)
|
||||||
tags = jsonutils.loads(response.text)['tags']
|
tags = jsonutils.loads(response.text)['tags']
|
||||||
self.assertEqual(6, len(tags))
|
self.assertEqual(6, len(tags))
|
||||||
|
|
||||||
# Attempt to create duplicate existing tag6
|
# Attempt to create duplicate existing tag6
|
||||||
data = jsonutils.dumps(
|
data = {
|
||||||
{"tags": [{"name": "tag6"}, {"name": "tag7"}, {"name": "tag8"}]}
|
"tags": [
|
||||||
)
|
{"name": "tag6"},
|
||||||
response = requests.post(path, headers=headers, data=data)
|
{"name": "tag7"},
|
||||||
|
{"name": "tag8"}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
response = self.api_post(path, headers=headers, json=data)
|
||||||
self.assertEqual(http.CONFLICT, response.status_code)
|
self.assertEqual(http.CONFLICT, response.status_code)
|
||||||
|
|
||||||
# Verify the previous 6 still exist
|
# Verify the previous 6 still exist
|
||||||
response = requests.get(path, headers=self._headers())
|
response = self.api_get(path, headers=self._headers())
|
||||||
self.assertEqual(http.OK, response.status_code)
|
self.assertEqual(http.OK, response.status_code)
|
||||||
tags = jsonutils.loads(response.text)['tags']
|
tags = jsonutils.loads(response.text)['tags']
|
||||||
self.assertEqual(6, len(tags))
|
self.assertEqual(6, len(tags))
|
||||||
@@ -195,11 +203,11 @@ class TestMetadefTags(metadef_base.MetadefFunctionalTestBase):
|
|||||||
for namespace in namespaces:
|
for namespace in namespaces:
|
||||||
headers = self._headers({'X-Tenant-Id': namespace['owner']})
|
headers = self._headers({'X-Tenant-Id': namespace['owner']})
|
||||||
tag_name = "tag_of_%s" % (namespace['namespace'])
|
tag_name = "tag_of_%s" % (namespace['namespace'])
|
||||||
path = self._url('/v2/metadefs/namespaces/%s/tags/%s' %
|
path = '/v2/metadefs/namespaces/%s/tags/%s' % (
|
||||||
(namespace['namespace'], tag_name))
|
namespace['namespace'], tag_name)
|
||||||
response = requests.post(path, headers=headers)
|
response = self.api_post(path, headers=headers)
|
||||||
self.assertEqual(http.CREATED, response.status_code)
|
self.assertEqual(http.CREATED, response.status_code)
|
||||||
tag_metadata = response.json()
|
tag_metadata = jsonutils.loads(response.text)
|
||||||
metadef_tags = dict()
|
metadef_tags = dict()
|
||||||
metadef_tags[namespace['namespace']] = tag_metadata['name']
|
metadef_tags[namespace['namespace']] = tag_metadata['name']
|
||||||
tags.append(metadef_tags)
|
tags.append(metadef_tags)
|
||||||
@@ -208,20 +216,20 @@ class TestMetadefTags(metadef_base.MetadefFunctionalTestBase):
|
|||||||
|
|
||||||
def _update_tags(self, path, headers, data):
|
def _update_tags(self, path, headers, data):
|
||||||
# The tag should be mutable
|
# The tag should be mutable
|
||||||
response = requests.put(path, headers=headers, json=data)
|
response = self.api_put(path, headers=headers, json=data)
|
||||||
self.assertEqual(http.OK, response.status_code, response.text)
|
self.assertEqual(http.OK, response.status_code, response.text)
|
||||||
# Returned metadata_tag should reflect the changes
|
# Returned metadata_tag should reflect the changes
|
||||||
metadata_tag = response.json()
|
metadata_tag = jsonutils.loads(response.text)
|
||||||
self.assertEqual(data['name'], metadata_tag['name'])
|
self.assertEqual(data['name'], metadata_tag['name'])
|
||||||
|
|
||||||
# Updates should persist across requests
|
# Updates should persist across requests
|
||||||
response = requests.get(path, headers=self._headers())
|
response = self.api_get(path, headers=self._headers())
|
||||||
self.assertEqual(http.OK, response.status_code)
|
self.assertEqual(http.OK, response.status_code)
|
||||||
self.assertEqual(data['name'], metadata_tag['name'])
|
self.assertEqual(data['name'], metadata_tag['name'])
|
||||||
|
|
||||||
def test_role_base_metadata_tags_lifecycle(self):
|
def test_role_base_metadata_tags_lifecycle(self):
|
||||||
# Create public and private namespaces for tenant1 and tenant2
|
# Create public and private namespaces for tenant1 and tenant2
|
||||||
path = self._url('/v2/metadefs/namespaces')
|
path = '/v2/metadefs/namespaces'
|
||||||
headers = self._headers({'content-type': 'application/json'})
|
headers = self._headers({'content-type': 'application/json'})
|
||||||
tenant1_namespaces = []
|
tenant1_namespaces = []
|
||||||
tenant2_namespaces = []
|
tenant2_namespaces = []
|
||||||
@@ -237,6 +245,7 @@ class TestMetadefTags(metadef_base.MetadefFunctionalTestBase):
|
|||||||
}
|
}
|
||||||
namespace = self.create_namespace(path, headers,
|
namespace = self.create_namespace(path, headers,
|
||||||
namespace_data)
|
namespace_data)
|
||||||
|
namespace = jsonutils.loads(namespace.text)
|
||||||
self.assertNamespacesEqual(namespace, namespace_data)
|
self.assertNamespacesEqual(namespace, namespace_data)
|
||||||
if tenant == self.tenant1:
|
if tenant == self.tenant1:
|
||||||
tenant1_namespaces.append(namespace)
|
tenant1_namespaces.append(namespace)
|
||||||
@@ -253,9 +262,9 @@ class TestMetadefTags(metadef_base.MetadefFunctionalTestBase):
|
|||||||
'X-Roles': 'reader,member'})
|
'X-Roles': 'reader,member'})
|
||||||
for tag in tags:
|
for tag in tags:
|
||||||
for namespace, tag_name in tag.items():
|
for namespace, tag_name in tag.items():
|
||||||
path = self._url('/v2/metadefs/namespaces/%s/tags/%s' %
|
path = '/v2/metadefs/namespaces/%s/tags/%s' % (
|
||||||
(namespace, tag_name))
|
namespace, tag_name)
|
||||||
response = requests.get(path, headers=headers)
|
response = self.api_get(path, headers=headers)
|
||||||
if namespace.split('_')[1] == 'public':
|
if namespace.split('_')[1] == 'public':
|
||||||
expected = http.OK
|
expected = http.OK
|
||||||
else:
|
else:
|
||||||
@@ -266,12 +275,11 @@ class TestMetadefTags(metadef_base.MetadefFunctionalTestBase):
|
|||||||
self.assertEqual(expected, response.status_code)
|
self.assertEqual(expected, response.status_code)
|
||||||
|
|
||||||
# Make sure the same holds for listing
|
# Make sure the same holds for listing
|
||||||
path = self._url(
|
path = '/v2/metadefs/namespaces/%s/tags' % namespace
|
||||||
'/v2/metadefs/namespaces/%s/tags' % namespace)
|
response = self.api_get(path, headers=headers)
|
||||||
response = requests.get(path, headers=headers)
|
|
||||||
self.assertEqual(expected, response.status_code)
|
self.assertEqual(expected, response.status_code)
|
||||||
if expected == http.OK:
|
if expected == http.OK:
|
||||||
resp_props = response.json()['tags']
|
resp_props = jsonutils.loads(response.text)['tags']
|
||||||
self.assertEqual(
|
self.assertEqual(
|
||||||
sorted(tag.values()),
|
sorted(tag.values()),
|
||||||
sorted([x['name']
|
sorted([x['name']
|
||||||
@@ -291,12 +299,12 @@ class TestMetadefTags(metadef_base.MetadefFunctionalTestBase):
|
|||||||
for namespace, tag_name in tag.items():
|
for namespace, tag_name in tag.items():
|
||||||
data = {
|
data = {
|
||||||
"name": tag_name}
|
"name": tag_name}
|
||||||
path = self._url('/v2/metadefs/namespaces/%s/tags/%s' %
|
path = '/v2/metadefs/namespaces/%s/tags/%s' % (
|
||||||
(namespace, tag_name))
|
namespace, tag_name)
|
||||||
|
|
||||||
# Update tag should fail with non admin role
|
# Update tag should fail with non admin role
|
||||||
headers['X-Roles'] = "reader,member"
|
headers['X-Roles'] = "reader,member"
|
||||||
response = requests.put(path, headers=headers, json=data)
|
response = self.api_put(path, headers=headers, json=data)
|
||||||
self.assertEqual(http.FORBIDDEN, response.status_code)
|
self.assertEqual(http.FORBIDDEN, response.status_code)
|
||||||
|
|
||||||
# Should work with admin role
|
# Should work with admin role
|
||||||
@@ -307,9 +315,9 @@ class TestMetadefTags(metadef_base.MetadefFunctionalTestBase):
|
|||||||
# Delete tags should not be allowed to non admin role
|
# Delete tags should not be allowed to non admin role
|
||||||
for tag in total_tags:
|
for tag in total_tags:
|
||||||
for namespace, tag_name in tag.items():
|
for namespace, tag_name in tag.items():
|
||||||
path = self._url('/v2/metadefs/namespaces/%s/tags/%s' %
|
path = '/v2/metadefs/namespaces/%s/tags/%s' % (
|
||||||
(namespace, tag_name))
|
namespace, tag_name)
|
||||||
response = requests.delete(
|
response = self.api_delete(
|
||||||
path, headers=self._headers({
|
path, headers=self._headers({
|
||||||
'X-Roles': 'reader,member',
|
'X-Roles': 'reader,member',
|
||||||
'X-Tenant-Id': namespace.split('_')[0]
|
'X-Tenant-Id': namespace.split('_')[0]
|
||||||
@@ -320,13 +328,13 @@ class TestMetadefTags(metadef_base.MetadefFunctionalTestBase):
|
|||||||
headers = self._headers()
|
headers = self._headers()
|
||||||
for tag in total_tags:
|
for tag in total_tags:
|
||||||
for namespace, tag_name in tag.items():
|
for namespace, tag_name in tag.items():
|
||||||
path = self._url('/v2/metadefs/namespaces/%s/tags/%s' %
|
path = '/v2/metadefs/namespaces/%s/tags/%s' % (
|
||||||
(namespace, tag_name))
|
namespace, tag_name)
|
||||||
response = requests.delete(path, headers=headers)
|
response = self.api_delete(path, headers=headers)
|
||||||
self.assertEqual(http.NO_CONTENT, response.status_code)
|
self.assertEqual(http.NO_CONTENT, response.status_code)
|
||||||
|
|
||||||
# Deleted tags should not be exist
|
# Deleted tags should not exist
|
||||||
response = requests.get(path, headers=headers)
|
response = self.api_get(path, headers=headers)
|
||||||
self.assertEqual(http.NOT_FOUND, response.status_code)
|
self.assertEqual(http.NOT_FOUND, response.status_code)
|
||||||
|
|
||||||
# Create multiple tags should not be allowed to non admin role
|
# Create multiple tags should not be allowed to non admin role
|
||||||
@@ -336,32 +344,29 @@ class TestMetadefTags(metadef_base.MetadefFunctionalTestBase):
|
|||||||
"tags": [{"name": "tag1"}, {"name": "tag2"}, {"name": "tag3"}]
|
"tags": [{"name": "tag1"}, {"name": "tag2"}, {"name": "tag3"}]
|
||||||
}
|
}
|
||||||
for namespace in tenant1_namespaces:
|
for namespace in tenant1_namespaces:
|
||||||
path = self._url('/v2/metadefs/namespaces/%s/tags' %
|
path = '/v2/metadefs/namespaces/%s/tags' % (
|
||||||
(namespace['namespace']))
|
namespace['namespace'])
|
||||||
response = requests.post(path, headers=headers, json=data)
|
response = self.api_post(path, headers=headers, json=data)
|
||||||
self.assertEqual(http.FORBIDDEN, response.status_code)
|
self.assertEqual(http.FORBIDDEN, response.status_code)
|
||||||
|
|
||||||
# Create multiple tags.
|
# Create multiple tags.
|
||||||
headers = self._headers({'content-type': 'application/json'})
|
headers = self._headers({'content-type': 'application/json'})
|
||||||
for namespace in tenant1_namespaces:
|
for namespace in tenant1_namespaces:
|
||||||
path = self._url('/v2/metadefs/namespaces/%s/tags' %
|
path = '/v2/metadefs/namespaces/%s/tags' % (namespace['namespace'])
|
||||||
(namespace['namespace']))
|
response = self.api_post(path, headers=headers, json=data)
|
||||||
response = requests.post(path, headers=headers, json=data)
|
|
||||||
self.assertEqual(http.CREATED, response.status_code)
|
self.assertEqual(http.CREATED, response.status_code)
|
||||||
|
|
||||||
# Delete multiple tags should not be allowed with non admin role
|
# Delete multiple tags should not be allowed with non admin role
|
||||||
headers = self._headers({'content-type': 'application/json',
|
headers = self._headers({'content-type': 'application/json',
|
||||||
'X-Roles': 'reader,member'})
|
'X-Roles': 'reader,member'})
|
||||||
for namespace in tenant1_namespaces:
|
for namespace in tenant1_namespaces:
|
||||||
path = self._url('/v2/metadefs/namespaces/%s/tags' %
|
path = '/v2/metadefs/namespaces/%s/tags' % (namespace['namespace'])
|
||||||
(namespace['namespace']))
|
response = self.api_delete(path, headers=headers)
|
||||||
response = requests.delete(path, headers=headers)
|
|
||||||
self.assertEqual(http.FORBIDDEN, response.status_code)
|
self.assertEqual(http.FORBIDDEN, response.status_code)
|
||||||
|
|
||||||
# Delete multiple tags created above created tags
|
# Delete multiple tags created above created tags
|
||||||
headers = self._headers()
|
headers = self._headers()
|
||||||
for namespace in tenant1_namespaces:
|
for namespace in tenant1_namespaces:
|
||||||
path = self._url('/v2/metadefs/namespaces/%s/tags' %
|
path = '/v2/metadefs/namespaces/%s/tags' % (namespace['namespace'])
|
||||||
(namespace['namespace']))
|
response = self.api_delete(path, headers=headers)
|
||||||
response = requests.delete(path, headers=headers)
|
|
||||||
self.assertEqual(http.NO_CONTENT, response.status_code)
|
self.assertEqual(http.NO_CONTENT, response.status_code)
|
||||||
|
Reference in New Issue
Block a user