diff options
Diffstat (limited to 'testapi/opnfv_testapi/resources')
-rw-r--r-- | testapi/opnfv_testapi/resources/handlers.py | 12 | ||||
-rw-r--r-- | testapi/opnfv_testapi/resources/models.py | 23 | ||||
-rw-r--r-- | testapi/opnfv_testapi/resources/scenario_handlers.py | 350 | ||||
-rw-r--r-- | testapi/opnfv_testapi/resources/scenario_models.py | 7 |
4 files changed, 368 insertions, 24 deletions
diff --git a/testapi/opnfv_testapi/resources/handlers.py b/testapi/opnfv_testapi/resources/handlers.py index 73afabe..ed55c70 100644 --- a/testapi/opnfv_testapi/resources/handlers.py +++ b/testapi/opnfv_testapi/resources/handlers.py @@ -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): @@ -189,6 +189,16 @@ class GenericApiHandler(web.RequestHandler): 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(): diff --git a/testapi/opnfv_testapi/resources/models.py b/testapi/opnfv_testapi/resources/models.py index e8fc532..6f04cc2 100644 --- a/testapi/opnfv_testapi/resources/models.py +++ b/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(v) + elif isinstance(v, list) and k in attr_parser: + value = [] + for item in v: + value.append(attr_parser[k].from_dict(item)) + + t.__setattr__(k, value) + + return t + @staticmethod def attr_parser(): return {} diff --git a/testapi/opnfv_testapi/resources/scenario_handlers.py b/testapi/opnfv_testapi/resources/scenario_handlers.py index 66e8559..bd06400 100644 --- a/testapi/opnfv_testapi/resources/scenario_handlers.py +++ b/testapi/opnfv_testapi/resources/scenario_handlers.py @@ -1,5 +1,7 @@ import functools +from opnfv_testapi.common import message +from opnfv_testapi.common import raises from opnfv_testapi.resources import handlers import opnfv_testapi.resources.scenario_models as models from opnfv_testapi.tornado_swagger import swagger @@ -138,6 +140,13 @@ class ScenarioUpdater(object): updates = { ('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, + ('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, } updates[(item, action)](self.data) @@ -178,6 +187,76 @@ class ScenarioUpdater(object): project.trust_indicators.append( models.ScenarioTI.from_dict(self.body)) + @iter_installers + @iter_versions + @iter_projects + def _update_requests_add_customs(self, project): + project.customs = list(set(project.customs + self.body)) + + @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.body, + project.customs) + + @iter_installers + @iter_versions + def _update_requests_add_projects(self, version): + exists = list() + malformat = list() + for n in self.body: + try: + f_n = models.ScenarioProject.from_dict_with_raise(n) + if not any(o.project == f_n.project for o in version.projects): + version.projects.append(f_n) + else: + exists.append(n['project']) + except Exception as e: + malformat.append(e.message) + if malformat: + raises.BadRequest(message.bad_format(malformat)) + elif exists: + raises.Conflict(message.exist('projects', exists)) + + @iter_installers + @iter_versions + def _update_requests_update_projects(self, version): + exists = list() + malformat = list() + projects = list() + for n in self.body: + try: + f_n = models.ScenarioProject.from_dict_with_raise(n) + if not any(o.project == f_n.project for o in projects): + projects.append(models.ScenarioProject.from_dict(n)) + else: + exists.append(n['project']) + except: + malformat.append(n) + if malformat: + raises.BadRequest(message.bad_format(malformat)) + elif exists: + raises.Forbidden(message.exist('projects', exists)) + version.projects = projects + + @iter_installers + @iter_versions + def _update_requests_delete_projects(self, version): + version.projects = self._remove_projects(version.projects) + + @iter_installers + @iter_versions + def _update_requests_change_owner(self, version): + version.owner = self.body + def _filter_installers(self, installers): return self._filter('installer', installers) @@ -187,11 +266,19 @@ class ScenarioUpdater(object): def _filter_projects(self, projects): return self._filter('project', projects) + def _remove_projects(self, projects): + return self._remove('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) not in self.body, + fields) + class GenericScenarioUpdateHandler(GenericScenarioHandler): def __init__(self, application, request, **kwargs): @@ -204,15 +291,15 @@ class GenericScenarioUpdateHandler(GenericScenarioHandler): self.item = None self.action = None - def do_post(self, scenario, item, action, locators): + def do_update(self, item, action, locators): self.item = item self.action = action - for k in locators.keys(): - v = self.get_query_argument(k) - setattr(self, k, v) - locators[k] = v - db_keys = ['name'] - self._update(query=self.set_query(locators=locators), db_keys=db_keys) + 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, @@ -247,16 +334,15 @@ class ScenarioScoresHandler(GenericScenarioUpdateHandler): @type project: L{string} @in project: query @required project: True - @rtype: L{Scenario} @return 200: score is created. @raise 404: scenario/installer/version/project not existed """ - self.do_post(scenario, - 'scores', - 'post', - locators={'installer': None, - 'version': None, - 'project': None}) + self.do_update('scores', + 'post', + locators={'scenario': scenario, + 'installer': None, + 'version': None, + 'project': None}) class ScenarioTIsHandler(GenericScenarioUpdateHandler): @@ -284,13 +370,235 @@ class ScenarioTIsHandler(GenericScenarioUpdateHandler): @type project: L{string} @in project: query @required project: True - @rtype: L{Scenario} @return 200: trust indicator is added. @raise 404: scenario/installer/version/project not existed """ - self.do_post(scenario, - 'trust_indicators', - 'post', - locators={'installer': None, - 'version': None, - 'project': None}) + 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}) + + +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}) + + +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{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: change owner success. + @raise 404: scenario/installer/version not existed + """ + self.do_update('owner', + 'put', + locators={'scenario': scenario, + 'installer': None, + 'version': None}) diff --git a/testapi/opnfv_testapi/resources/scenario_models.py b/testapi/opnfv_testapi/resources/scenario_models.py index 9f5a074..7d07707 100644 --- a/testapi/opnfv_testapi/resources/scenario_models.py +++ b/testapi/opnfv_testapi/resources/scenario_models.py @@ -74,7 +74,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 +84,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) |