Implement 'all' artifact type
Change-Id: Ia3bbe4f76af29e269ce25e67a6d2324e1ec57927
This commit is contained in:
parent
a4feb466da
commit
ead97e6d33
@ -57,7 +57,8 @@ class ArtifactAPI(base_api.BaseDBAPI):
|
||||
|
||||
def list(self, context, filters, marker, limit, sort, latest):
|
||||
session = api.get_session()
|
||||
filters.append(('type_name', None, 'eq', None, self.type))
|
||||
if self.type != 'all':
|
||||
filters.append(('type_name', None, 'eq', None, self.type))
|
||||
return api.get_all(context=context, session=session, filters=filters,
|
||||
marker=marker, limit=limit, sort=sort,
|
||||
latest=latest)
|
||||
|
34
glare/objects/all.py
Normal file
34
glare/objects/all.py
Normal file
@ -0,0 +1,34 @@
|
||||
# Copyright (c) 2016 Mirantis, Inc.
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License"); you may
|
||||
# not use this file except in compliance with the License. You may obtain
|
||||
# a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||
# License for the specific language governing permissions and limitations
|
||||
# under the License.
|
||||
|
||||
from oslo_versionedobjects import fields
|
||||
|
||||
from glare.objects import base
|
||||
from glare.objects.meta import attribute
|
||||
|
||||
|
||||
Field = attribute.Attribute.init
|
||||
|
||||
|
||||
class All(base.ReadOnlyMixin, base.BaseArtifact):
|
||||
"""Artifact type that allows to get artifacts regardless of their type"""
|
||||
|
||||
fields = {
|
||||
'type_name': Field(fields.StringField,
|
||||
description="Name of artifact type."),
|
||||
}
|
||||
|
||||
@classmethod
|
||||
def get_type_name(cls):
|
||||
return "all"
|
@ -1200,3 +1200,57 @@ class BaseArtifact(base.VersionedObject):
|
||||
'required': ['name']}
|
||||
|
||||
return schemas
|
||||
|
||||
|
||||
class ReadOnlyMixin(object):
|
||||
"""Mixin that disables all modifying actions on artifacts."""
|
||||
|
||||
@classmethod
|
||||
def create(cls, context, values):
|
||||
raise exception.Forbidden("This type is read only.")
|
||||
|
||||
@classmethod
|
||||
def update(cls, context, af, values):
|
||||
raise exception.Forbidden("This type is read only.")
|
||||
|
||||
@classmethod
|
||||
def get_action_for_updates(cls, context, artifact, updates, registry):
|
||||
raise exception.Forbidden("This type is read only.")
|
||||
|
||||
@classmethod
|
||||
def delete(cls, context, af):
|
||||
raise exception.Forbidden("This type is read only.")
|
||||
|
||||
@classmethod
|
||||
def activate(cls, context, af, values):
|
||||
raise exception.Forbidden("This type is read only.")
|
||||
|
||||
@classmethod
|
||||
def reactivate(cls, context, af, values):
|
||||
raise exception.Forbidden("This type is read only.")
|
||||
|
||||
@classmethod
|
||||
def deactivate(cls, context, af, values):
|
||||
raise exception.Forbidden("This type is read only.")
|
||||
|
||||
@classmethod
|
||||
def publish(cls, context, af, values):
|
||||
raise exception.Forbidden("This type is read only.")
|
||||
|
||||
@classmethod
|
||||
def upload_blob(cls, context, af, field_name, fd, content_type):
|
||||
raise exception.Forbidden("This type is read only.")
|
||||
|
||||
@classmethod
|
||||
def upload_blob_dict(cls, context, af, field_name, blob_key, fd,
|
||||
content_type):
|
||||
raise exception.Forbidden("This type is read only.")
|
||||
|
||||
@classmethod
|
||||
def add_blob_location(cls, context, af, field_name, location, blob_meta):
|
||||
raise exception.Forbidden("This type is read only.")
|
||||
|
||||
@classmethod
|
||||
def add_blob_dict_location(cls, context, af, field_name,
|
||||
blob_key, location, blob_meta):
|
||||
raise exception.Forbidden("This type is read only.")
|
||||
|
@ -103,7 +103,7 @@ class ArtifactRegistry(vo_base.VersionedObjectRegistry):
|
||||
supported_types = []
|
||||
for module in modules:
|
||||
supported_types.extend(get_subclasses(module, base.BaseArtifact))
|
||||
for type_name in CONF.glare.enabled_artifact_types:
|
||||
for type_name in set(CONF.glare.enabled_artifact_types + ['all']):
|
||||
for af_type in supported_types:
|
||||
if type_name == af_type.get_type_name():
|
||||
cls._validate_artifact_type(af_type)
|
||||
|
183
glare/tests/functional/base.py
Normal file
183
glare/tests/functional/base.py
Normal file
@ -0,0 +1,183 @@
|
||||
# Copyright (c) 2016 Mirantis, Inc.
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License"); you may
|
||||
# not use this file except in compliance with the License. You may obtain
|
||||
# a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||
# License for the specific language governing permissions and limitations
|
||||
# under the License.
|
||||
|
||||
import uuid
|
||||
|
||||
from oslo_serialization import jsonutils
|
||||
import requests
|
||||
|
||||
from glare.tests import functional
|
||||
|
||||
|
||||
def sort_results(lst, target='name'):
|
||||
return sorted(lst, key=lambda x: x[target])
|
||||
|
||||
|
||||
class TestArtifact(functional.FunctionalTest):
|
||||
enabled_types = (u'sample_artifact', u'images', u'heat_templates',
|
||||
u'heat_environments', u'tosca_templates',
|
||||
u'murano_packages')
|
||||
|
||||
users = {
|
||||
'user1': {
|
||||
'id': str(uuid.uuid4()),
|
||||
'tenant_id': str(uuid.uuid4()),
|
||||
'token': str(uuid.uuid4()),
|
||||
'role': 'member'
|
||||
},
|
||||
'user2': {
|
||||
'id': str(uuid.uuid4()),
|
||||
'tenant_id': str(uuid.uuid4()),
|
||||
'token': str(uuid.uuid4()),
|
||||
'role': 'member'
|
||||
},
|
||||
'admin': {
|
||||
'id': str(uuid.uuid4()),
|
||||
'tenant_id': str(uuid.uuid4()),
|
||||
'token': str(uuid.uuid4()),
|
||||
'role': 'admin'
|
||||
},
|
||||
'anonymous': {
|
||||
'id': None,
|
||||
'tenant_id': None,
|
||||
'token': None,
|
||||
'role': None
|
||||
}
|
||||
}
|
||||
|
||||
def setUp(self):
|
||||
super(TestArtifact, self).setUp()
|
||||
|
||||
self.set_user('user1')
|
||||
self.glare_server.deployment_flavor = 'noauth'
|
||||
|
||||
self.glare_server.enabled_artifact_types = ','.join(
|
||||
self.enabled_types)
|
||||
self.glare_server.custom_artifact_types_modules = (
|
||||
'glare.tests.functional.sample_artifact')
|
||||
self.start_servers(**self.__dict__.copy())
|
||||
|
||||
def tearDown(self):
|
||||
self.stop_servers()
|
||||
self._reset_database(self.glare_server.sql_connection)
|
||||
super(TestArtifact, self).tearDown()
|
||||
|
||||
def _url(self, path):
|
||||
if 'schemas' in path:
|
||||
return 'http://127.0.0.1:%d%s' % (self.glare_port, path)
|
||||
else:
|
||||
return 'http://127.0.0.1:%d/artifacts%s' % (self.glare_port, path)
|
||||
|
||||
def set_user(self, username):
|
||||
if username not in self.users:
|
||||
raise KeyError
|
||||
self.current_user = username
|
||||
|
||||
def _headers(self, custom_headers=None):
|
||||
base_headers = {
|
||||
'X-Identity-Status': 'Confirmed',
|
||||
'X-Auth-Token': self.users[self.current_user]['token'],
|
||||
'X-User-Id': self.users[self.current_user]['id'],
|
||||
'X-Tenant-Id': self.users[self.current_user]['tenant_id'],
|
||||
'X-Project-Id': self.users[self.current_user]['tenant_id'],
|
||||
'X-Roles': self.users[self.current_user]['role'],
|
||||
}
|
||||
base_headers.update(custom_headers or {})
|
||||
return base_headers
|
||||
|
||||
def create_artifact(self, data=None, status=201,
|
||||
type_name='sample_artifact'):
|
||||
return self.post('/' + type_name, data or {}, status=status)
|
||||
|
||||
def _check_artifact_method(self, method, url, data=None, status=200,
|
||||
headers=None):
|
||||
if not headers:
|
||||
headers = self._headers()
|
||||
else:
|
||||
headers = self._headers(headers)
|
||||
headers.setdefault("Content-Type", "application/json")
|
||||
if 'application/json' in headers['Content-Type'] and data is not None:
|
||||
data = jsonutils.dumps(data)
|
||||
response = getattr(requests, method)(self._url(url), headers=headers,
|
||||
data=data)
|
||||
self.assertEqual(status, response.status_code, response.text)
|
||||
if status >= 400:
|
||||
return response.text
|
||||
if ("application/json" in response.headers["content-type"] or
|
||||
"application/schema+json" in response.headers["content-type"]):
|
||||
return jsonutils.loads(response.text)
|
||||
return response.text
|
||||
|
||||
def post(self, url, data=None, status=201, headers=None):
|
||||
return self._check_artifact_method("post", url, data, status=status,
|
||||
headers=headers)
|
||||
|
||||
def get(self, url, status=200, headers=None):
|
||||
return self._check_artifact_method("get", url, status=status,
|
||||
headers=headers)
|
||||
|
||||
def delete(self, url, status=204):
|
||||
response = requests.delete(self._url(url), headers=self._headers())
|
||||
self.assertEqual(status, response.status_code, response.text)
|
||||
return response.text
|
||||
|
||||
def patch(self, url, data, status=200, headers=None):
|
||||
if headers is None:
|
||||
headers = {}
|
||||
if 'Content-Type' not in headers:
|
||||
headers.update({'Content-Type': 'application/json-patch+json'})
|
||||
return self._check_artifact_method("patch", url, data, status=status,
|
||||
headers=headers)
|
||||
|
||||
def put(self, url, data=None, status=200, headers=None):
|
||||
return self._check_artifact_method("put", url, data, status=status,
|
||||
headers=headers)
|
||||
|
||||
# the test cases below are written in accordance with use cases
|
||||
# each test tries to cover separate use case in Glare
|
||||
# all code inside each test tries to cover all operators and data
|
||||
# involved in use case execution
|
||||
# each tests represents part of artifact lifecycle
|
||||
# so we can easily define where is the failed code
|
||||
|
||||
make_active = [{"op": "replace", "path": "/status", "value": "active"}]
|
||||
|
||||
def activate_with_admin(self, artifact_id, status=200):
|
||||
cur_user = self.current_user
|
||||
self.set_user('admin')
|
||||
url = '/sample_artifact/%s' % artifact_id
|
||||
af = self.patch(url=url, data=self.make_active, status=status)
|
||||
self.set_user(cur_user)
|
||||
return af
|
||||
|
||||
make_deactivated = [{"op": "replace", "path": "/status",
|
||||
"value": "deactivated"}]
|
||||
|
||||
def deactivate_with_admin(self, artifact_id, status=200):
|
||||
cur_user = self.current_user
|
||||
self.set_user('admin')
|
||||
url = '/sample_artifact/%s' % artifact_id
|
||||
af = self.patch(url=url, data=self.make_deactivated, status=status)
|
||||
self.set_user(cur_user)
|
||||
return af
|
||||
|
||||
make_public = [{"op": "replace", "path": "/visibility", "value": "public"}]
|
||||
|
||||
def publish_with_admin(self, artifact_id, status=200):
|
||||
cur_user = self.current_user
|
||||
self.set_user('admin')
|
||||
url = '/sample_artifact/%s' % artifact_id
|
||||
af = self.patch(url=url, data=self.make_public, status=status)
|
||||
self.set_user(cur_user)
|
||||
return af
|
96
glare/tests/functional/test_all.py
Normal file
96
glare/tests/functional/test_all.py
Normal file
@ -0,0 +1,96 @@
|
||||
# Copyright (c) 2016 Mirantis, Inc.
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License"); you may
|
||||
# not use this file except in compliance with the License. You may obtain
|
||||
# a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||
# License for the specific language governing permissions and limitations
|
||||
# under the License.
|
||||
|
||||
from glare.tests.functional import base
|
||||
|
||||
|
||||
class TestAll(base.TestArtifact):
|
||||
|
||||
def test_all(self):
|
||||
for type_name in self.enabled_types:
|
||||
if type_name == 'all':
|
||||
continue
|
||||
for i in range(3):
|
||||
for j in range(3):
|
||||
self.create_artifact(
|
||||
data={'name': '%s_%d' % (type_name, i),
|
||||
'version': '%d' % j,
|
||||
'tags': ['tag%s' % i]},
|
||||
type_name=type_name)
|
||||
|
||||
# get all possible artifacts
|
||||
url = '/all?sort=name:asc&limit=100'
|
||||
res = self.get(url=url, status=200)['all']
|
||||
from pprint import pformat
|
||||
self.assertEqual(54, len(res), pformat(res))
|
||||
|
||||
# get artifacts with latest versions
|
||||
url = '/all?version=latest&sort=name:asc'
|
||||
res = self.get(url=url, status=200)['all']
|
||||
self.assertEqual(18, len(res))
|
||||
for art in res:
|
||||
self.assertEqual('2.0.0', art['version'])
|
||||
|
||||
# get images only
|
||||
url = '/all?type_name=images&sort=name:asc'
|
||||
res = self.get(url=url, status=200)['all']
|
||||
self.assertEqual(9, len(res))
|
||||
for art in res:
|
||||
self.assertEqual('images', art['type_name'])
|
||||
|
||||
# get images and heat_templates
|
||||
url = '/all?type_name=in:images,heat_templates&sort=name:asc'
|
||||
res = self.get(url=url, status=200)['all']
|
||||
self.assertEqual(18, len(res))
|
||||
for art in res:
|
||||
self.assertIn(art['type_name'], ('images', 'heat_templates'))
|
||||
|
||||
def test_all_readonlyness(self):
|
||||
self.create_artifact(data={'name': 'all'}, type_name='all', status=403)
|
||||
art = self.create_artifact(data={'name': 'image'}, type_name='images')
|
||||
|
||||
url = '/all/%s' % art['id']
|
||||
|
||||
headers = {'Content-Type': 'application/octet-stream'}
|
||||
# upload to 'all' is forbidden
|
||||
self.put(url=url + '/icon', data='data', status=403,
|
||||
headers=headers)
|
||||
|
||||
# update 'all' is forbidden
|
||||
data = [{
|
||||
"op": "replace",
|
||||
"path": "/description",
|
||||
"value": "text"
|
||||
}]
|
||||
self.patch(url=url, data=data, status=403)
|
||||
|
||||
# activation is forbidden
|
||||
data = [{
|
||||
"op": "replace",
|
||||
"path": "/status",
|
||||
"value": "active"
|
||||
}]
|
||||
self.patch(url=url, data=data, status=403)
|
||||
|
||||
# publishing is forbidden
|
||||
data = [{
|
||||
"op": "replace",
|
||||
"path": "/visibility",
|
||||
"value": "public"
|
||||
}]
|
||||
self.patch(url=url, data=data, status=403)
|
||||
|
||||
# get is okay
|
||||
new_art = self.get(url=url)
|
||||
self.assertEqual(new_art['id'], art['id'])
|
@ -17,168 +17,15 @@ import hashlib
|
||||
import uuid
|
||||
|
||||
from oslo_serialization import jsonutils
|
||||
import requests
|
||||
|
||||
from glare.tests import functional
|
||||
from glare.tests.functional import base
|
||||
|
||||
|
||||
def sort_results(lst, target='name'):
|
||||
return sorted(lst, key=lambda x: x[target])
|
||||
|
||||
|
||||
class TestArtifact(functional.FunctionalTest):
|
||||
|
||||
users = {
|
||||
'user1': {
|
||||
'id': str(uuid.uuid4()),
|
||||
'tenant_id': str(uuid.uuid4()),
|
||||
'token': str(uuid.uuid4()),
|
||||
'role': 'member'
|
||||
},
|
||||
'user2': {
|
||||
'id': str(uuid.uuid4()),
|
||||
'tenant_id': str(uuid.uuid4()),
|
||||
'token': str(uuid.uuid4()),
|
||||
'role': 'member'
|
||||
},
|
||||
'admin': {
|
||||
'id': str(uuid.uuid4()),
|
||||
'tenant_id': str(uuid.uuid4()),
|
||||
'token': str(uuid.uuid4()),
|
||||
'role': 'admin'
|
||||
},
|
||||
'anonymous': {
|
||||
'id': None,
|
||||
'tenant_id': None,
|
||||
'token': None,
|
||||
'role': None
|
||||
}
|
||||
}
|
||||
|
||||
def setUp(self):
|
||||
super(TestArtifact, self).setUp()
|
||||
self.set_user('user1')
|
||||
self.glare_server.deployment_flavor = 'noauth'
|
||||
self.glare_server.enabled_artifact_types = 'sample_artifact'
|
||||
self.glare_server.custom_artifact_types_modules = (
|
||||
'glare.tests.functional.sample_artifact')
|
||||
self.start_servers(**self.__dict__.copy())
|
||||
|
||||
def tearDown(self):
|
||||
self.stop_servers()
|
||||
self._reset_database(self.glare_server.sql_connection)
|
||||
super(TestArtifact, self).tearDown()
|
||||
|
||||
def _url(self, path):
|
||||
if 'schemas' in path:
|
||||
return 'http://127.0.0.1:%d%s' % (self.glare_port, path)
|
||||
else:
|
||||
return 'http://127.0.0.1:%d/artifacts%s' % (self.glare_port, path)
|
||||
|
||||
def set_user(self, username):
|
||||
if username not in self.users:
|
||||
raise KeyError
|
||||
self.current_user = username
|
||||
|
||||
def _headers(self, custom_headers=None):
|
||||
base_headers = {
|
||||
'X-Identity-Status': 'Confirmed',
|
||||
'X-Auth-Token': self.users[self.current_user]['token'],
|
||||
'X-User-Id': self.users[self.current_user]['id'],
|
||||
'X-Tenant-Id': self.users[self.current_user]['tenant_id'],
|
||||
'X-Project-Id': self.users[self.current_user]['tenant_id'],
|
||||
'X-Roles': self.users[self.current_user]['role'],
|
||||
}
|
||||
base_headers.update(custom_headers or {})
|
||||
return base_headers
|
||||
|
||||
def create_artifact(self, data=None, status=201):
|
||||
return self.post('/sample_artifact', data or {}, status=status)
|
||||
|
||||
def _check_artifact_method(self, method, url, data=None, status=200,
|
||||
headers=None):
|
||||
if not headers:
|
||||
headers = self._headers()
|
||||
else:
|
||||
headers = self._headers(headers)
|
||||
headers.setdefault("Content-Type", "application/json")
|
||||
if 'application/json' in headers['Content-Type'] and data is not None:
|
||||
data = jsonutils.dumps(data)
|
||||
response = getattr(requests, method)(self._url(url), headers=headers,
|
||||
data=data)
|
||||
self.assertEqual(status, response.status_code, response.text)
|
||||
if status >= 400:
|
||||
return response.text
|
||||
if ("application/json" in response.headers["content-type"] or
|
||||
"application/schema+json" in response.headers["content-type"]):
|
||||
return jsonutils.loads(response.text)
|
||||
return response.text
|
||||
|
||||
def post(self, url, data=None, status=201, headers=None):
|
||||
return self._check_artifact_method("post", url, data, status=status,
|
||||
headers=headers)
|
||||
|
||||
def get(self, url, status=200, headers=None):
|
||||
return self._check_artifact_method("get", url, status=status,
|
||||
headers=headers)
|
||||
|
||||
def delete(self, url, status=204):
|
||||
response = requests.delete(self._url(url), headers=self._headers())
|
||||
self.assertEqual(status, response.status_code, response.text)
|
||||
return response.text
|
||||
|
||||
def patch(self, url, data, status=200, headers=None):
|
||||
if headers is None:
|
||||
headers = {}
|
||||
if 'Content-Type' not in headers:
|
||||
headers.update({'Content-Type': 'application/json-patch+json'})
|
||||
return self._check_artifact_method("patch", url, data, status=status,
|
||||
headers=headers)
|
||||
|
||||
def put(self, url, data=None, status=200, headers=None):
|
||||
return self._check_artifact_method("put", url, data, status=status,
|
||||
headers=headers)
|
||||
|
||||
# the test cases below are written in accordance with use cases
|
||||
# each test tries to cover separate use case in Glare
|
||||
# all code inside each test tries to cover all operators and data
|
||||
# involved in use case execution
|
||||
# each tests represents part of artifact lifecycle
|
||||
# so we can easily define where is the failed code
|
||||
|
||||
make_active = [{"op": "replace", "path": "/status", "value": "active"}]
|
||||
|
||||
def activate_with_admin(self, artifact_id, status=200):
|
||||
cur_user = self.current_user
|
||||
self.set_user('admin')
|
||||
url = '/sample_artifact/%s' % artifact_id
|
||||
af = self.patch(url=url, data=self.make_active, status=status)
|
||||
self.set_user(cur_user)
|
||||
return af
|
||||
|
||||
make_deactivated = [{"op": "replace", "path": "/status",
|
||||
"value": "deactivated"}]
|
||||
|
||||
def deactivate_with_admin(self, artifact_id, status=200):
|
||||
cur_user = self.current_user
|
||||
self.set_user('admin')
|
||||
url = '/sample_artifact/%s' % artifact_id
|
||||
af = self.patch(url=url, data=self.make_deactivated, status=status)
|
||||
self.set_user(cur_user)
|
||||
return af
|
||||
|
||||
make_public = [{"op": "replace", "path": "/visibility", "value": "public"}]
|
||||
|
||||
def publish_with_admin(self, artifact_id, status=200):
|
||||
cur_user = self.current_user
|
||||
self.set_user('admin')
|
||||
url = '/sample_artifact/%s' % artifact_id
|
||||
af = self.patch(url=url, data=self.make_public, status=status)
|
||||
self.set_user(cur_user)
|
||||
return af
|
||||
|
||||
|
||||
class TestList(TestArtifact):
|
||||
class TestList(base.TestArtifact):
|
||||
def test_list_marker_and_limit(self):
|
||||
# Create artifacts
|
||||
art_list = [self.create_artifact({'name': 'name%s' % i,
|
||||
@ -806,7 +653,7 @@ class TestList(TestArtifact):
|
||||
self.assertEqual(response_url, result['first'])
|
||||
|
||||
|
||||
class TestBlobs(TestArtifact):
|
||||
class TestBlobs(base.TestArtifact):
|
||||
def test_blob_dicts(self):
|
||||
# Getting empty artifact list
|
||||
url = '/sample_artifact'
|
||||
@ -1005,7 +852,7 @@ class TestBlobs(TestArtifact):
|
||||
status=400, headers=headers)
|
||||
|
||||
|
||||
class TestTags(TestArtifact):
|
||||
class TestTags(base.TestArtifact):
|
||||
def test_tags(self):
|
||||
# Create artifact
|
||||
art = self.create_artifact({'name': 'name5',
|
||||
@ -1064,7 +911,7 @@ class TestTags(TestArtifact):
|
||||
self.patch(url=url, data=patch, status=400)
|
||||
|
||||
|
||||
class TestArtifactOps(TestArtifact):
|
||||
class TestArtifactOps(base.TestArtifact):
|
||||
def test_create(self):
|
||||
"""All tests related to artifact creation"""
|
||||
# check that cannot create artifact for non-existent artifact type
|
||||
@ -1346,7 +1193,7 @@ class TestArtifactOps(TestArtifact):
|
||||
self.assertEqual("active", deactive_art["status"])
|
||||
|
||||
|
||||
class TestUpdate(TestArtifact):
|
||||
class TestUpdate(base.TestArtifact):
|
||||
def test_update_artifact_before_activate(self):
|
||||
"""Test updates for artifact before activation"""
|
||||
# create artifact to update
|
||||
@ -2262,7 +2109,7 @@ class TestUpdate(TestArtifact):
|
||||
self.patch(url=url, data=data, status=400)
|
||||
|
||||
|
||||
class TestDependencies(TestArtifact):
|
||||
class TestDependencies(base.TestArtifact):
|
||||
def test_manage_dependencies(self):
|
||||
some_af = self.create_artifact(data={"name": "test_af"})
|
||||
dep_af = self.create_artifact(data={"name": "test_dep_af"})
|
||||
|
@ -15,11 +15,8 @@
|
||||
|
||||
import jsonschema
|
||||
|
||||
from oslo_serialization import jsonutils
|
||||
import requests
|
||||
|
||||
from glare.common import utils
|
||||
from glare.tests import functional
|
||||
from glare.tests.functional import base
|
||||
|
||||
fixture_base_props = {
|
||||
u'activated_at': {
|
||||
@ -231,10 +228,6 @@ fixture_base_props = {
|
||||
u'type': u'string'}
|
||||
}
|
||||
|
||||
enabled_artifact_types = (
|
||||
u'sample_artifact', u'images', u'heat_templates',
|
||||
u'heat_environments', u'tosca_templates', u'murano_packages')
|
||||
|
||||
|
||||
def generate_type_props(props):
|
||||
props.update(fixture_base_props)
|
||||
@ -976,61 +969,38 @@ fixtures = {
|
||||
u'required': [u'name'],
|
||||
u'version': u'1.0',
|
||||
u'title': u'Artifact type heat_environments of version 1.0',
|
||||
u'type': u'object'},
|
||||
u'all': {
|
||||
u'name': u'all',
|
||||
u'properties': generate_type_props({
|
||||
u'type_name': {u'description': u'Name of artifact type.',
|
||||
u'filter_ops': [u'eq', u'neq', u'in'],
|
||||
u'maxLength': 255,
|
||||
u'type': [u'string', u'null']},
|
||||
|
||||
}),
|
||||
u'required': [u'name'],
|
||||
u'version': u'1.0',
|
||||
u'title': u'Artifact type all of version 1.0',
|
||||
u'type': u'object'}
|
||||
}
|
||||
|
||||
|
||||
class TestSchemas(functional.FunctionalTest):
|
||||
|
||||
def setUp(self):
|
||||
super(TestSchemas, self).setUp()
|
||||
self.glare_server.deployment_flavor = 'noauth'
|
||||
|
||||
self.glare_server.enabled_artifact_types = ','.join(
|
||||
enabled_artifact_types)
|
||||
self.glare_server.custom_artifact_types_modules = (
|
||||
'glare.tests.functional.sample_artifact')
|
||||
self.start_servers(**self.__dict__.copy())
|
||||
|
||||
def tearDown(self):
|
||||
self.stop_servers()
|
||||
self._reset_database(self.glare_server.sql_connection)
|
||||
super(TestSchemas, self).tearDown()
|
||||
|
||||
def _url(self, path):
|
||||
return 'http://127.0.0.1:%d%s' % (self.glare_port, path)
|
||||
|
||||
def _check_artifact_method(self, url, status=200):
|
||||
headers = {
|
||||
'X-Identity-Status': 'Confirmed',
|
||||
}
|
||||
response = requests.get(self._url(url), headers=headers)
|
||||
self.assertEqual(status, response.status_code, response.text)
|
||||
if status >= 400:
|
||||
return response.text
|
||||
if ("application/json" in response.headers["content-type"] or
|
||||
"application/schema+json" in response.headers["content-type"]):
|
||||
return jsonutils.loads(response.text)
|
||||
return response.text
|
||||
|
||||
def get(self, url, status=200, headers=None):
|
||||
return self._check_artifact_method(url, status=status)
|
||||
|
||||
class TestSchemas(base.TestArtifact):
|
||||
def test_schemas(self):
|
||||
|
||||
# Get list schemas of artifacts
|
||||
result = self.get(url='/schemas')
|
||||
self.assertEqual(fixtures, result['schemas'], utils.DictDiffer(
|
||||
result['schemas'], fixtures))
|
||||
|
||||
# Get schemas for specific artifact type
|
||||
for at in enabled_artifact_types:
|
||||
for at in self.enabled_types:
|
||||
result = self.get(url='/schemas/%s' % at)
|
||||
self.assertEqual(fixtures[at], result['schemas'][at],
|
||||
utils.DictDiffer(
|
||||
result['schemas'][at]['properties'],
|
||||
fixtures[at]['properties']))
|
||||
|
||||
# Get list schemas of artifacts
|
||||
result = self.get(url='/schemas')
|
||||
self.assertEqual(fixtures, result['schemas'], utils.DictDiffer(
|
||||
result['schemas'], fixtures))
|
||||
|
||||
# Get schema of sample_artifact
|
||||
result = self.get(url='/schemas/sample_artifact')
|
||||
self.assertEqual(fixtures['sample_artifact'],
|
||||
|
Loading…
Reference in New Issue
Block a user