diff options
Diffstat (limited to 'utils/test/testapi/opnfv_testapi/resources')
6 files changed, 818 insertions, 169 deletions
diff --git a/utils/test/testapi/opnfv_testapi/resources/handlers.py b/utils/test/testapi/opnfv_testapi/resources/handlers.py index 2fc31ca45..ed55c7028 100644 --- a/utils/test/testapi/opnfv_testapi/resources/handlers.py +++ b/utils/test/testapi/opnfv_testapi/resources/handlers.py @@ -20,8 +20,8 @@ # feng.xiaowei@zte.com.cn remove DashboardHandler 5-30-2016 ############################################################################## -from datetime import datetime import json +from datetime import datetime from tornado import gen from tornado import web @@ -29,6 +29,7 @@ from tornado import web from opnfv_testapi.common import check from opnfv_testapi.common import message from opnfv_testapi.common import raises +from opnfv_testapi.db import api as dbapi from opnfv_testapi.resources import models from opnfv_testapi.tornado_swagger import swagger @@ -38,7 +39,6 @@ DEFAULT_REPRESENTATION = "application/json" class GenericApiHandler(web.RequestHandler): def __init__(self, application, request, **kwargs): super(GenericApiHandler, self).__init__(application, request, **kwargs) - self.db = self.settings["db"] self.json_args = None self.table = None self.table_cls = None @@ -50,7 +50,7 @@ class GenericApiHandler(web.RequestHandler): self.auth = self.settings["auth"] def prepare(self): - if self.request.method != "GET" and self.request.method != "DELETE": + if self.request.body: if self.request.headers.get("Content-Type") is not None: if self.request.headers["Content-Type"].startswith( DEFAULT_REPRESENTATION): @@ -90,8 +90,7 @@ class GenericApiHandler(web.RequestHandler): if self.table != 'results': data.creation_date = datetime.now() - _id = yield self._eval_db(self.table, 'insert', data.format(), - check_keys=False) + _id = yield dbapi.db_save(self.table, data.format()) if 'name' in self.json_args: resource = data.name else: @@ -101,22 +100,72 @@ class GenericApiHandler(web.RequestHandler): @web.asynchronous @gen.coroutine def _list(self, query=None, res_op=None, *args, **kwargs): + sort = kwargs.get('sort') + page = kwargs.get('page', 0) + last = kwargs.get('last', 0) + per_page = kwargs.get('per_page', 0) if query is None: query = {} - data = [] - cursor = self._eval_db(self.table, 'find', query) - if 'sort' in kwargs: - cursor = cursor.sort(kwargs.get('sort')) - if 'last' in kwargs: - cursor = cursor.limit(kwargs.get('last')) - while (yield cursor.fetch_next): - data.append(self.format_data(cursor.next_object())) + pipelines = list() + pipelines.append({'$match': query}) + + total_pages = 0 + data = list() + cursor = dbapi.db_list(self.table, query) + records_count = yield cursor.count() + if records_count > 0: + if page > 0: + total_pages, return_nr = self._calc_total_pages(records_count, + last, + page, + per_page) + pipelines = self._set_pipelines(pipelines, + sort, + return_nr, + page, + per_page) + cursor = dbapi.db_aggregate(self.table, pipelines) + while (yield cursor.fetch_next): + data.append(self.format_data(cursor.next_object())) if res_op is None: res = {self.table: data} else: res = res_op(data, *args) + if page > 0: + res.update({ + 'pagination': { + 'current_page': kwargs.get('page'), + 'total_pages': total_pages + } + }) self.finish_request(res) + @staticmethod + def _calc_total_pages(records_count, last, page, per_page): + records_nr = records_count + if (records_count > last) and (last > 0): + records_nr = last + + total_pages, remainder = divmod(records_nr, per_page) + if remainder > 0: + total_pages += 1 + if page > 1 and page > total_pages: + raises.BadRequest( + 'Request page > total_pages [{}]'.format(total_pages)) + return total_pages, records_nr + + @staticmethod + def _set_pipelines(pipelines, sort, return_nr, page, per_page): + if sort: + pipelines.append({'$sort': sort}) + + over = (page - 1) * per_page + left = return_nr - over + pipelines.append({'$skip': over}) + pipelines.append({'$limit': per_page if per_page < left else left}) + + return pipelines + @web.asynchronous @gen.coroutine @check.not_exist @@ -126,7 +175,7 @@ class GenericApiHandler(web.RequestHandler): @check.authenticate @check.not_exist def _delete(self, data, query=None): - yield self._eval_db(self.table, 'remove', query) + yield dbapi.db_delete(self.table, query) self.finish_request() @check.authenticate @@ -136,11 +185,20 @@ class GenericApiHandler(web.RequestHandler): def _update(self, data, query=None, **kwargs): data = self.table_cls.from_dict(data) update_req = self._update_requests(data) - yield self._eval_db(self.table, 'update', query, update_req, - check_keys=False) + yield dbapi.db_update(self.table, query, update_req) update_req['_id'] = str(data._id) self.finish_request(update_req) + @check.authenticate + @check.no_body + @check.not_exist + @check.updated_one_not_exist + def pure_update(self, data, query=None, **kwargs): + data = self.table_cls.from_dict(data) + update_req = self._update_requests(data) + yield dbapi.db_update(self.table, query, update_req) + self.finish_request() + def _update_requests(self, data): request = dict() for k, v in self.json_args.iteritems(): @@ -180,23 +238,6 @@ class GenericApiHandler(web.RequestHandler): query[key] = new return query if not equal else dict() - def _eval_db(self, table, method, *args, **kwargs): - exec_collection = self.db.__getattr__(table) - return exec_collection.__getattribute__(method)(*args, **kwargs) - - def _eval_db_find_one(self, query, table=None): - if table is None: - table = self.table - return self._eval_db(table, 'find_one', query) - - def db_save(self, collection, data): - self._eval_db(collection, 'insert', data, check_keys=False) - - def db_find_one(self, query, collection=None): - if not collection: - collection = self.table - return self._eval_db(collection, 'find_one', query) - class VersionHandler(GenericApiHandler): @swagger.operation(nickname='listAllVersions') diff --git a/utils/test/testapi/opnfv_testapi/resources/models.py b/utils/test/testapi/opnfv_testapi/resources/models.py index e8fc532b7..e70a6ed23 100644 --- a/utils/test/testapi/opnfv_testapi/resources/models.py +++ b/utils/test/testapi/opnfv_testapi/resources/models.py @@ -48,6 +48,29 @@ class ModelBase(object): return t + @classmethod + def from_dict_with_raise(cls, a_dict): + if a_dict is None: + return None + + attr_parser = cls.attr_parser() + t = cls() + for k, v in a_dict.iteritems(): + if k not in t.__dict__: + raise AttributeError( + '{} has no attribute {}'.format(cls.__name__, k)) + value = v + if isinstance(v, dict) and k in attr_parser: + value = attr_parser[k].from_dict_with_raise(v) + elif isinstance(v, list) and k in attr_parser: + value = [] + for item in v: + value.append(attr_parser[k].from_dict_with_raise(item)) + + t.__setattr__(k, value) + + return t + @staticmethod def attr_parser(): return {} diff --git a/utils/test/testapi/opnfv_testapi/resources/result_handlers.py b/utils/test/testapi/opnfv_testapi/resources/result_handlers.py index 824a89e58..9389d266d 100644 --- a/utils/test/testapi/opnfv_testapi/resources/result_handlers.py +++ b/utils/test/testapi/opnfv_testapi/resources/result_handlers.py @@ -6,16 +6,20 @@ # which accompanies this distribution, and is available at # http://www.apache.org/licenses/LICENSE-2.0 ############################################################################## +import logging from datetime import datetime from datetime import timedelta +import json from bson import objectid +from opnfv_testapi.common.config import CONF from opnfv_testapi.common import message from opnfv_testapi.common import raises from opnfv_testapi.resources import handlers from opnfv_testapi.resources import result_models from opnfv_testapi.tornado_swagger import swagger +from opnfv_testapi.ui.auth import constants as auth_const class GenericResultHandler(handlers.GenericApiHandler): @@ -37,6 +41,7 @@ class GenericResultHandler(handlers.GenericApiHandler): query = dict() date_range = dict() + query['public'] = {'$not': {'$eq': 'false'}} for k in self.request.query_arguments.keys(): v = self.get_query_argument(k) if k == 'project' or k == 'pod' or k == 'case': @@ -53,10 +58,24 @@ class GenericResultHandler(handlers.GenericApiHandler): date_range.update({'$gte': str(v)}) elif k == 'to': date_range.update({'$lt': str(v)}) - elif k != 'last' and k != 'page': + elif k == 'signed': + openid = self.get_secure_cookie(auth_const.OPENID) + role = self.get_secure_cookie(auth_const.ROLE) + logging.info('role:%s', role) + if role: + del query['public'] + if role != "reviewer": + query['user'] = openid + elif k not in ['last', 'page', 'descend']: query[k] = v if date_range: query['start_date'] = date_range + + # if $lt is not provided, + # empty/None/null/'' start_date will also be returned + if 'start_date' in query and '$lt' not in query['start_date']: + query['start_date'].update({'$lt': str(datetime.now())}) + return query @@ -81,9 +100,10 @@ class ResultsCLHandler(GenericResultHandler): - criteria : the global criteria status passed or failed - trust_indicator : evaluate the stability of the test case to avoid running systematically long and stable test case + - signed : get logined user result GET /results/project=functest&case=vPing&version=Arno-R1 \ - &pod=pod_name&period=15 + &pod=pod_name&period=15&signed @return 200: all test results consist with query, empty list if no result is found @rtype: L{TestResults} @@ -135,22 +155,41 @@ class ResultsCLHandler(GenericResultHandler): @type last: L{string} @in last: query @required last: False + @param page: which page to list, default to 1 + @type page: L{int} + @in page: query + @required page: False @param trust_indicator: must be float @type trust_indicator: L{float} @in trust_indicator: query @required trust_indicator: False + @param signed: user results or all results + @type signed: L{string} + @in signed: query + @required signed: False + @param descend: true, newest2oldest; false, oldest2newest + @type descend: L{string} + @in descend: query + @required descend: False """ - last = self.get_query_argument('last', 0) - if last is not None: - last = self.get_int('last', last) + def descend_limit(): + descend = self.get_query_argument('descend', 'true') + return -1 if descend.lower() == 'true' else 1 + + def last_limit(): + return self.get_int('last', self.get_query_argument('last', 0)) - page = self.get_query_argument('page', 0) - if page: - last = 20 + def page_limit(): + return self.get_int('page', self.get_query_argument('page', 1)) - self._list(query=self.set_query(), - sort=[('start_date', -1)], - last=last) + limitations = { + 'sort': {'_id': descend_limit()}, + 'last': last_limit(), + 'page': page_limit(), + 'per_page': CONF.api_results_per_page + } + + self._list(query=self.set_query(), **limitations) @swagger.operation(nickname="createTestResult") def post(self): @@ -164,6 +203,9 @@ class ResultsCLHandler(GenericResultHandler): @raise 404: pod/project/testcase not exist @raise 400: body/pod_name/project_name/case_name not provided """ + self._post() + + def _post(self): def pod_query(): return {'name': self.json_args.get('pod_name')} @@ -178,9 +220,39 @@ class ResultsCLHandler(GenericResultHandler): carriers = [('pods', pod_query), ('projects', project_query), ('testcases', testcase_query)] + self._create(miss_fields=miss_fields, carriers=carriers) +class ResultsUploadHandler(ResultsCLHandler): + @swagger.operation(nickname="uploadTestResult") + def post(self): + """ + @description: upload and create a test result + @param body: result to be created + @type body: L{ResultCreateRequest} + @in body: body + @rtype: L{CreateResponse} + @return 200: result is created. + @raise 404: pod/project/testcase not exist + @raise 400: body/pod_name/project_name/case_name not provided + """ + logging.info('file upload') + fileinfo = self.request.files['file'][0] + is_public = self.get_body_argument('public') + logging.warning('public:%s', is_public) + logging.info('results is :%s', fileinfo['filename']) + logging.info('results is :%s', fileinfo['body']) + self.json_args = json.loads(fileinfo['body']).copy() + self.json_args['public'] = is_public + + openid = self.get_secure_cookie(auth_const.OPENID) + if openid: + self.json_args['user'] = openid + + super(ResultsUploadHandler, self)._post() + + class ResultsGURHandler(GenericResultHandler): @swagger.operation(nickname='getTestResultById') def get(self, result_id): diff --git a/utils/test/testapi/opnfv_testapi/resources/result_models.py b/utils/test/testapi/opnfv_testapi/resources/result_models.py index 62a6dacff..890bf8220 100644 --- a/utils/test/testapi/opnfv_testapi/resources/result_models.py +++ b/utils/test/testapi/opnfv_testapi/resources/result_models.py @@ -54,6 +54,8 @@ class ResultCreateRequest(models.ModelBase): build_tag=None, scenario=None, criteria=None, + user=None, + public="true", trust_indicator=None): self.pod_name = pod_name self.project_name = project_name @@ -66,6 +68,8 @@ class ResultCreateRequest(models.ModelBase): self.build_tag = build_tag self.scenario = scenario self.criteria = criteria + self.user = user + self.public = public self.trust_indicator = trust_indicator if trust_indicator else TI(0) @@ -89,7 +93,7 @@ class TestResult(models.ModelBase): pod_name=None, installer=None, version=None, start_date=None, stop_date=None, details=None, build_tag=None, scenario=None, criteria=None, - trust_indicator=None): + user=None, public="true", trust_indicator=None): self._id = _id self.case_name = case_name self.project_name = project_name @@ -102,6 +106,8 @@ class TestResult(models.ModelBase): self.build_tag = build_tag self.scenario = scenario self.criteria = criteria + self.user = user + self.public = public self.trust_indicator = trust_indicator @staticmethod diff --git a/utils/test/testapi/opnfv_testapi/resources/scenario_handlers.py b/utils/test/testapi/opnfv_testapi/resources/scenario_handlers.py index 5d420a56e..e9c19a7a4 100644 --- a/utils/test/testapi/opnfv_testapi/resources/scenario_handlers.py +++ b/utils/test/testapi/opnfv_testapi/resources/scenario_handlers.py @@ -15,6 +15,24 @@ class GenericScenarioHandler(handlers.GenericApiHandler): self.table = self.db_scenarios self.table_cls = models.Scenario + def set_query(self, locators): + query = dict() + elem_query = dict() + for k, v in locators.iteritems(): + if k == 'scenario': + query['name'] = v + elif k == 'installer': + elem_query["installer"] = v + elif k == 'version': + elem_query["versions.version"] = v + elif k == 'project': + elem_query["versions.projects.project"] = v + else: + query[k] = v + if elem_query: + query['installers'] = {'$elemMatch': elem_query} + return query + class ScenariosCLHandler(GenericScenarioHandler): @swagger.operation(nickname="queryScenarios") @@ -96,10 +114,10 @@ class ScenarioGURHandler(GenericScenarioHandler): self._get_one(query={'name': name}) pass - @swagger.operation(nickname="updateScenarioByName") + @swagger.operation(nickname="updateScenarioName") def put(self, name): """ - @description: update a single scenario by name + @description: update scenario, only rename is supported currently @param body: fields to be updated @type body: L{ScenarioUpdateRequest} @in body: body @@ -119,164 +137,639 @@ class ScenarioGURHandler(GenericScenarioHandler): @return 200: delete success @raise 404: scenario not exist: """ - self._delete(query={'name': name}) - def _update_query(self, keys, data): - query = dict() - if self._is_rename(): - new = self._term.get('name') - if data.get('name') != new: - query['name'] = new - return query +class ScenarioUpdater(object): + def __init__(self, data, body=None, + installer=None, version=None, project=None): + self.data = data + self.body = body + self.installer = installer + self.version = version + self.project = project - def _update_requests(self, data): + def update(self, item, action): updates = { - ('name', 'update'): self._update_requests_rename, - ('installer', 'add'): self._update_requests_add_installer, - ('installer', 'delete'): self._update_requests_delete_installer, - ('version', 'add'): self._update_requests_add_version, - ('version', 'delete'): self._update_requests_delete_version, - ('owner', 'update'): self._update_requests_change_owner, - ('project', 'add'): self._update_requests_add_project, - ('project', 'delete'): self._update_requests_delete_project, - ('customs', 'add'): self._update_requests_add_customs, + ('scores', 'post'): self._update_requests_add_score, + ('trust_indicators', 'post'): self._update_requests_add_ti, + ('customs', 'post'): self._update_requests_add_customs, + ('customs', 'put'): self._update_requests_update_customs, ('customs', 'delete'): self._update_requests_delete_customs, - ('score', 'add'): self._update_requests_add_score, - ('trust_indicator', 'add'): self._update_requests_add_ti, + ('projects', 'post'): self._update_requests_add_projects, + ('projects', 'put'): self._update_requests_update_projects, + ('projects', 'delete'): self._update_requests_delete_projects, + ('owner', 'put'): self._update_requests_change_owner, + ('versions', 'post'): self._update_requests_add_versions, + ('versions', 'put'): self._update_requests_update_versions, + ('versions', 'delete'): self._update_requests_delete_versions, + ('installers', 'post'): self._update_requests_add_installers, + ('installers', 'put'): self._update_requests_update_installers, + ('installers', 'delete'): self._update_requests_delete_installers, } + updates[(item, action)](self.data) - updates[(self._field, self._op)](data) - - return data.format() + return self.data.format() - def _iter_installers(xstep): + def iter_installers(xstep): @functools.wraps(xstep) def magic(self, data): [xstep(self, installer) for installer in self._filter_installers(data.installers)] return magic - def _iter_versions(xstep): + def iter_versions(xstep): @functools.wraps(xstep) def magic(self, installer): [xstep(self, version) for version in (self._filter_versions(installer.versions))] return magic - def _iter_projects(xstep): + def iter_projects(xstep): @functools.wraps(xstep) def magic(self, version): [xstep(self, project) for project in (self._filter_projects(version.projects))] return magic - def _update_requests_rename(self, data): - data.name = self._term.get('name') - if not data.name: - raises.BadRequest(message.missing('name')) - - def _update_requests_add_installer(self, data): - data.installers.append(models.ScenarioInstaller.from_dict(self._term)) - - def _update_requests_delete_installer(self, data): - data.installers = self._remove_installers(data.installers) - - @_iter_installers - def _update_requests_add_version(self, installer): - installer.versions.append(models.ScenarioVersion.from_dict(self._term)) - - @_iter_installers - def _update_requests_delete_version(self, installer): - installer.versions = self._remove_versions(installer.versions) - - @_iter_installers - @_iter_versions - def _update_requests_change_owner(self, version): - version.owner = self._term.get('owner') - - @_iter_installers - @_iter_versions - def _update_requests_add_project(self, version): - version.projects.append(models.ScenarioProject.from_dict(self._term)) + @iter_installers + @iter_versions + @iter_projects + def _update_requests_add_score(self, project): + project.scores.append( + models.ScenarioScore.from_dict(self.body)) - @_iter_installers - @_iter_versions - def _update_requests_delete_project(self, version): - version.projects = self._remove_projects(version.projects) + @iter_installers + @iter_versions + @iter_projects + def _update_requests_add_ti(self, project): + project.trust_indicators.append( + models.ScenarioTI.from_dict(self.body)) - @_iter_installers - @_iter_versions - @_iter_projects + @iter_installers + @iter_versions + @iter_projects def _update_requests_add_customs(self, project): - project.customs = list(set(project.customs + self._term)) + project.customs = list(set(project.customs + self.body)) - @_iter_installers - @_iter_versions - @_iter_projects + @iter_installers + @iter_versions + @iter_projects + def _update_requests_update_customs(self, project): + project.customs = list(set(self.body)) + + @iter_installers + @iter_versions + @iter_projects def _update_requests_delete_customs(self, project): project.customs = filter( - lambda f: f not in self._term, + lambda f: f not in self.body, project.customs) - @_iter_installers - @_iter_versions - @_iter_projects - def _update_requests_add_score(self, project): - project.scores.append( - models.ScenarioScore.from_dict(self._term)) + @iter_installers + @iter_versions + def _update_requests_add_projects(self, version): + version.projects = self._update_with_body(models.ScenarioProject, + 'project', + version.projects) + + @iter_installers + @iter_versions + def _update_requests_update_projects(self, version): + version.projects = self._update_with_body(models.ScenarioProject, + 'project', + list()) + + @iter_installers + @iter_versions + def _update_requests_delete_projects(self, version): + version.projects = self._remove_projects(version.projects) - @_iter_installers - @_iter_versions - @_iter_projects - def _update_requests_add_ti(self, project): - project.trust_indicators.append( - models.ScenarioTI.from_dict(self._term)) + @iter_installers + @iter_versions + def _update_requests_change_owner(self, version): + version.owner = self.body.get('owner') + + @iter_installers + def _update_requests_add_versions(self, installer): + installer.versions = self._update_with_body(models.ScenarioVersion, + 'version', + installer.versions) + + @iter_installers + def _update_requests_update_versions(self, installer): + installer.versions = self._update_with_body(models.ScenarioVersion, + 'version', + list()) + + @iter_installers + def _update_requests_delete_versions(self, installer): + installer.versions = self._remove_versions(installer.versions) + + def _update_requests_add_installers(self, scenario): + scenario.installers = self._update_with_body(models.ScenarioInstaller, + 'installer', + scenario.installers) + + def _update_requests_update_installers(self, scenario): + scenario.installers = self._update_with_body(models.ScenarioInstaller, + 'installer', + list()) + + def _update_requests_delete_installers(self, scenario): + scenario.installers = self._remove_installers(scenario.installers) + + def _update_with_body(self, clazz, field, withs): + exists = list() + malformat = list() + for new in self.body: + try: + format_new = clazz.from_dict_with_raise(new) + new_name = getattr(format_new, field) + if not any(getattr(o, field) == new_name for o in withs): + withs.append(format_new) + else: + exists.append(new_name) + except Exception as error: + malformat.append(error.message) + if malformat: + raises.BadRequest(message.bad_format(malformat)) + elif exists: + raises.Conflict(message.exist('{}s'.format(field), exists)) + return withs - def _is_rename(self): - return self._field == 'name' and self._op == 'update' + def _filter_installers(self, installers): + return self._filter('installer', installers) def _remove_installers(self, installers): return self._remove('installer', installers) - def _filter_installers(self, installers): - return self._filter('installer', installers) + def _filter_versions(self, versions): + return self._filter('version', versions) def _remove_versions(self, versions): return self._remove('version', versions) - def _filter_versions(self, versions): - return self._filter('version', versions) + def _filter_projects(self, projects): + return self._filter('project', projects) def _remove_projects(self, projects): return self._remove('project', projects) - def _filter_projects(self, projects): - return self._filter('project', projects) + def _filter(self, item, items): + return filter( + lambda f: getattr(f, item) == getattr(self, item), + items) def _remove(self, field, fields): return filter( - lambda f: getattr(f, field) != self._locate.get(field), + lambda f: getattr(f, field) not in self.body, fields) - def _filter(self, field, fields): - return filter( - lambda f: getattr(f, field) == self._locate.get(field), - fields) - @property - def _field(self): - return self.json_args.get('field') +class GenericScenarioUpdateHandler(GenericScenarioHandler): + def __init__(self, application, request, **kwargs): + super(GenericScenarioUpdateHandler, self).__init__(application, + request, + **kwargs) + self.installer = None + self.version = None + self.project = None + self.item = None + self.action = None + + def do_update(self, item, action, locators): + self.item = item + self.action = action + for k, v in locators.iteritems(): + if not v: + v = self.get_query_argument(k) + setattr(self, k, v) + locators[k] = v + self.pure_update(query=self.set_query(locators=locators)) + + def _update_requests(self, data): + return ScenarioUpdater(data, + self.json_args, + self.installer, + self.version, + self.project).update(self.item, self.action) + + +class ScenarioScoresHandler(GenericScenarioUpdateHandler): + @swagger.operation(nickname="addScoreRecord") + def post(self, scenario): + """ + @description: add a new score record + @notes: add a new score record to a project + POST /api/v1/scenarios/<scenario_name>/scores? \ + installer=<installer_name>& \ + version=<version_name>& \ + project=<project_name> + @param body: score to be added + @type body: L{ScenarioScore} + @in body: body + @param installer: installer type + @type installer: L{string} + @in installer: query + @required installer: True + @param version: version + @type version: L{string} + @in version: query + @required version: True + @param project: project name + @type project: L{string} + @in project: query + @required project: True + @return 200: score is created. + @raise 404: scenario/installer/version/project not existed + """ + self.do_update('scores', + 'post', + locators={'scenario': scenario, + 'installer': None, + 'version': None, + 'project': None}) + + +class ScenarioTIsHandler(GenericScenarioUpdateHandler): + @swagger.operation(nickname="addTrustIndicatorRecord") + def post(self, scenario): + """ + @description: add a new trust indicator record + @notes: add a new trust indicator record to a project + POST /api/v1/scenarios/<scenario_name>/trust_indicators? \ + installer=<installer_name>& \ + version=<version_name>& \ + project=<project_name> + @param body: trust indicator to be added + @type body: L{ScenarioTI} + @in body: body + @param installer: installer type + @type installer: L{string} + @in installer: query + @required installer: True + @param version: version + @type version: L{string} + @in version: query + @required version: True + @param project: project name + @type project: L{string} + @in project: query + @required project: True + @return 200: trust indicator is added. + @raise 404: scenario/installer/version/project not existed + """ + self.do_update('trust_indicators', + 'post', + locators={'scenario': scenario, + 'installer': None, + 'version': None, + 'project': None}) + + +class ScenarioCustomsHandler(GenericScenarioUpdateHandler): + @swagger.operation(nickname="addCustomizedTestCases") + def post(self, scenario): + """ + @description: add customized test cases + @notes: add several test cases to a project + POST /api/v1/scenarios/<scenario_name>/customs? \ + installer=<installer_name>& \ + version=<version_name>& \ + project=<project_name> + @param body: test cases to be added + @type body: C{list} of L{string} + @in body: body + @param installer: installer type + @type installer: L{string} + @in installer: query + @required installer: True + @param version: version + @type version: L{string} + @in version: query + @required version: True + @param project: project name + @type project: L{string} + @in project: query + @required project: True + @return 200: test cases are added. + @raise 404: scenario/installer/version/project not existed + """ + self.do_update('customs', + 'post', + locators={'scenario': scenario, + 'installer': None, + 'version': None, + 'project': None}) + + @swagger.operation(nickname="updateCustomizedTestCases") + def put(self, scenario): + """ + @description: update customized test cases + @notes: substitute all the customized test cases + PUT /api/v1/scenarios/<scenario_name>/customs? \ + installer=<installer_name>& \ + version=<version_name>& \ + project=<project_name> + @param body: new supported test cases + @type body: C{list} of L{string} + @in body: body + @param installer: installer type + @type installer: L{string} + @in installer: query + @required installer: True + @param version: version + @type version: L{string} + @in version: query + @required version: True + @param project: project name + @type project: L{string} + @in project: query + @required project: True + @return 200: substitute test cases success. + @raise 404: scenario/installer/version/project not existed + """ + self.do_update('customs', + 'put', + locators={'scenario': scenario, + 'installer': None, + 'version': None, + 'project': None}) + + @swagger.operation(nickname="deleteCustomizedTestCases") + def delete(self, scenario): + """ + @description: delete one or several customized test cases + @notes: delete one or some customized test cases + DELETE /api/v1/scenarios/<scenario_name>/customs? \ + installer=<installer_name>& \ + version=<version_name>& \ + project=<project_name> + @param body: test case(s) to be deleted + @type body: C{list} of L{string} + @in body: body + @param installer: installer type + @type installer: L{string} + @in installer: query + @required installer: True + @param version: version + @type version: L{string} + @in version: query + @required version: True + @param project: project name + @type project: L{string} + @in project: query + @required project: True + @return 200: delete test case(s) success. + @raise 404: scenario/installer/version/project not existed + """ + self.do_update('customs', + 'delete', + locators={'scenario': scenario, + 'installer': None, + 'version': None, + 'project': None}) - @property - def _op(self): - return self.json_args.get('op') - @property - def _locate(self): - return self.json_args.get('locate') +class ScenarioProjectsHandler(GenericScenarioUpdateHandler): + @swagger.operation(nickname="addProjectsUnderScenario") + def post(self, scenario): + """ + @description: add projects to scenario + @notes: add one or multiple projects + POST /api/v1/scenarios/<scenario_name>/projects? \ + installer=<installer_name>& \ + version=<version_name> + @param body: projects to be added + @type body: C{list} of L{ScenarioProject} + @in body: body + @param installer: installer type + @type installer: L{string} + @in installer: query + @required installer: True + @param version: version + @type version: L{string} + @in version: query + @required version: True + @return 200: projects are added. + @raise 400: bad schema + @raise 409: conflict, project already exists + @raise 404: scenario/installer/version not existed + """ + self.do_update('projects', + 'post', + locators={'scenario': scenario, + 'installer': None, + 'version': None}) + + @swagger.operation(nickname="updateScenarioProjects") + def put(self, scenario): + """ + @description: replace all projects + @notes: substitute all projects, delete existed ones with new provides + PUT /api/v1/scenarios/<scenario_name>/projects? \ + installer=<installer_name>& \ + version=<version_name> + @param body: new projects + @type body: C{list} of L{ScenarioProject} + @in body: body + @param installer: installer type + @type installer: L{string} + @in installer: query + @required installer: True + @param version: version + @type version: L{string} + @in version: query + @required version: True + @return 200: replace projects success. + @raise 400: bad schema + @raise 404: scenario/installer/version not existed + """ + self.do_update('projects', + 'put', + locators={'scenario': scenario, + 'installer': None, + 'version': None}) + + @swagger.operation(nickname="deleteProjectsUnderScenario") + def delete(self, scenario): + """ + @description: delete one or multiple projects + @notes: delete one or multiple projects + DELETE /api/v1/scenarios/<scenario_name>/projects? \ + installer=<installer_name>& \ + version=<version_name> + @param body: projects(names) to be deleted + @type body: C{list} of L{string} + @in body: body + @param installer: installer type + @type installer: L{string} + @in installer: query + @required installer: True + @param version: version + @type version: L{string} + @in version: query + @required version: True + @return 200: delete project(s) success. + @raise 404: scenario/installer/version not existed + """ + self.do_update('projects', + 'delete', + locators={'scenario': scenario, + 'installer': None, + 'version': None}) - @property - def _term(self): - return self.json_args.get('term') + +class ScenarioOwnerHandler(GenericScenarioUpdateHandler): + @swagger.operation(nickname="changeScenarioOwner") + def put(self, scenario): + """ + @description: change scenario owner + @notes: substitute all projects, delete existed ones with new provides + PUT /api/v1/scenarios/<scenario_name>/owner? \ + installer=<installer_name>& \ + version=<version_name> + @param body: new owner + @type body: L{ScenarioChangeOwnerRequest} + @in body: body + @param installer: installer type + @type installer: L{string} + @in installer: query + @required installer: True + @param version: version + @type version: L{string} + @in version: query + @required version: True + @return 200: change owner success. + @raise 404: scenario/installer/version not existed + """ + self.do_update('owner', + 'put', + locators={'scenario': scenario, + 'installer': None, + 'version': None}) + + +class ScenarioVersionsHandler(GenericScenarioUpdateHandler): + @swagger.operation(nickname="addVersionsUnderScenario") + def post(self, scenario): + """ + @description: add versions to scenario + @notes: add one or multiple versions + POST /api/v1/scenarios/<scenario_name>/versions? \ + installer=<installer_name> + @param body: versions to be added + @type body: C{list} of L{ScenarioVersion} + @in body: body + @param installer: installer type + @type installer: L{string} + @in installer: query + @required installer: True + @return 200: versions are added. + @raise 400: bad schema + @raise 409: conflict, version already exists + @raise 404: scenario/installer not exist + """ + self.do_update('versions', + 'post', + locators={'scenario': scenario, + 'installer': None}) + + @swagger.operation(nickname="updateVersionsUnderScenario") + def put(self, scenario): + """ + @description: replace all versions + @notes: substitute all versions as a totality + PUT /api/v1/scenarios/<scenario_name>/versions? \ + installer=<installer_name> + @param body: new versions + @type body: C{list} of L{ScenarioVersion} + @in body: body + @param installer: installer type + @type installer: L{string} + @in installer: query + @required installer: True + @return 200: replace versions success. + @raise 400: bad schema + @raise 404: scenario/installer not exist + """ + self.do_update('versions', + 'put', + locators={'scenario': scenario, + 'installer': None}) + + @swagger.operation(nickname="deleteVersionsUnderScenario") + def delete(self, scenario): + """ + @description: delete one or multiple versions + @notes: delete one or multiple versions + DELETE /api/v1/scenarios/<scenario_name>/versions? \ + installer=<installer_name> + @param body: versions(names) to be deleted + @type body: C{list} of L{string} + @in body: body + @param installer: installer type + @type installer: L{string} + @in installer: query + @required installer: True + @return 200: delete versions success. + @raise 404: scenario/installer not exist + """ + self.do_update('versions', + 'delete', + locators={'scenario': scenario, + 'installer': None}) + + +class ScenarioInstallersHandler(GenericScenarioUpdateHandler): + @swagger.operation(nickname="addInstallersUnderScenario") + def post(self, scenario): + """ + @description: add installers to scenario + @notes: add one or multiple installers + POST /api/v1/scenarios/<scenario_name>/installers + @param body: installers to be added + @type body: C{list} of L{ScenarioInstaller} + @in body: body + @return 200: installers are added. + @raise 400: bad schema + @raise 409: conflict, installer already exists + @raise 404: scenario not exist + """ + self.do_update('installers', + 'post', + locators={'scenario': scenario}) + + @swagger.operation(nickname="updateInstallersUnderScenario") + def put(self, scenario): + """ + @description: replace all installers + @notes: substitute all installers as a totality + PUT /api/v1/scenarios/<scenario_name>/installers + @param body: new installers + @type body: C{list} of L{ScenarioInstaller} + @in body: body + @return 200: replace versions success. + @raise 400: bad schema + @raise 404: scenario/installer not exist + """ + self.do_update('installers', + 'put', + locators={'scenario': scenario}) + + @swagger.operation(nickname="deleteInstallersUnderScenario") + def delete(self, scenario): + """ + @description: delete one or multiple installers + @notes: delete one or multiple installers + DELETE /api/v1/scenarios/<scenario_name>/installers + @param body: installers(names) to be deleted + @type body: C{list} of L{string} + @in body: body + @return 200: delete versions success. + @raise 404: scenario/installer not exist + """ + self.do_update('installers', + 'delete', + locators={'scenario': scenario}) diff --git a/utils/test/testapi/opnfv_testapi/resources/scenario_models.py b/utils/test/testapi/opnfv_testapi/resources/scenario_models.py index 467cff241..d950ed1d7 100644 --- a/utils/test/testapi/opnfv_testapi/resources/scenario_models.py +++ b/utils/test/testapi/opnfv_testapi/resources/scenario_models.py @@ -16,6 +16,13 @@ class ScenarioTI(models.ModelBase): self.date = date self.status = status + def __eq__(self, other): + return (self.date == other.date and + self.status == other.status) + + def __ne__(self, other): + return not self.__eq__(other) + @swagger.model() class ScenarioScore(models.ModelBase): @@ -23,6 +30,13 @@ class ScenarioScore(models.ModelBase): self.date = date self.score = score + def __eq__(self, other): + return (self.date == other.date and + self.score == other.score) + + def __ne__(self, other): + return not self.__eq__(other) + @swagger.model() class ScenarioProject(models.ModelBase): @@ -50,10 +64,10 @@ class ScenarioProject(models.ModelBase): 'trust_indicators': ScenarioTI} def __eq__(self, other): - return [self.project == other.project and + return (self.project == other.project and self._customs_eq(other) and self._scores_eq(other) and - self._ti_eq(other)] + self._ti_eq(other)) def __ne__(self, other): return not self.__eq__(other) @@ -62,10 +76,10 @@ class ScenarioProject(models.ModelBase): return set(self.customs) == set(other.customs) def _scores_eq(self, other): - return set(self.scores) == set(other.scores) + return self.scores == other.scores def _ti_eq(self, other): - return set(self.trust_indicators) == set(other.trust_indicators) + return self.trust_indicators == other.trust_indicators @swagger.model() @@ -74,7 +88,8 @@ class ScenarioVersion(models.ModelBase): @property projects: @ptype projects: C{list} of L{ScenarioProject} """ - def __init__(self, version=None, projects=None): + def __init__(self, owner=None, version=None, projects=None): + self.owner = owner self.version = version self.projects = list_default(projects) @@ -83,7 +98,9 @@ class ScenarioVersion(models.ModelBase): return {'projects': ScenarioProject} def __eq__(self, other): - return [self.version == other.version and self._projects_eq(other)] + return (self.version == other.version and + self.owner == other.owner and + self._projects_eq(other)) def __ne__(self, other): return not self.__eq__(other) @@ -113,7 +130,7 @@ class ScenarioInstaller(models.ModelBase): return {'versions': ScenarioVersion} def __eq__(self, other): - return [self.installer == other.installer and self._versions_eq(other)] + return (self.installer == other.installer and self._versions_eq(other)) def __ne__(self, other): return not self.__eq__(other) @@ -144,18 +161,15 @@ class ScenarioCreateRequest(models.ModelBase): @swagger.model() +class ScenarioChangeOwnerRequest(models.ModelBase): + def __init__(self, owner=None): + self.owner = owner + + +@swagger.model() class ScenarioUpdateRequest(models.ModelBase): - """ - @property field: update field - @property op: add/delete/update - @property locate: information used to locate the field - @property term: new value - """ - def __init__(self, field=None, op=None, locate=None, term=None): - self.field = field - self.op = op - self.locate = dict_default(locate) - self.term = dict_default(term) + def __init__(self, name=None): + self.name = name @swagger.model() @@ -178,7 +192,7 @@ class Scenario(models.ModelBase): return not self.__eq__(other) def __eq__(self, other): - return [self.name == other.name and self._installers_eq(other)] + return (self.name == other.name and self._installers_eq(other)) def _installers_eq(self, other): for s_install in self.installers: |