From: SerenaFeng Date: Wed, 23 Aug 2017 06:04:59 +0000 (+0800) Subject: update versions under scenario X-Git-Url: https://gerrit.opnfv.org/gerrit/gitweb?a=commitdiff_plain;h=1e3f7ceed2ddab94711aa92f6945a38c63101368;p=releng.git update versions under scenario 1. post, add one or more new versions 2. update, replace existed version as a totality 3. delete, delete one or more versions by name 4. in post&update, if schema is not consistent with ScenarioVersion model, BadRequest will be raised(only extra keys will be detected currently) 5. in post, if project already exist, return Conflict with already exist message 6. in update, if a version appears more than once, also return Conflict with already exist message 7. add update with conflict unittest for projects Change-Id: I0d2c8a5567f3abce7b0313a64e18303af02cc002 Signed-off-by: SerenaFeng --- diff --git a/utils/test/testapi/opnfv_testapi/resources/models.py b/utils/test/testapi/opnfv_testapi/resources/models.py index 6f04cc236..e70a6ed23 100644 --- a/utils/test/testapi/opnfv_testapi/resources/models.py +++ b/utils/test/testapi/opnfv_testapi/resources/models.py @@ -61,11 +61,11 @@ class ModelBase(object): '{} 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) + 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(item)) + value.append(attr_parser[k].from_dict_with_raise(item)) t.__setattr__(k, value) diff --git a/utils/test/testapi/opnfv_testapi/resources/scenario_handlers.py b/utils/test/testapi/opnfv_testapi/resources/scenario_handlers.py index d215d18b9..d6918a69b 100644 --- a/utils/test/testapi/opnfv_testapi/resources/scenario_handlers.py +++ b/utils/test/testapi/opnfv_testapi/resources/scenario_handlers.py @@ -147,6 +147,9 @@ class ScenarioUpdater(object): ('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, } updates[(item, action)](self.data) @@ -210,42 +213,16 @@ class ScenarioUpdater(object): @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)) + version.projects = self._update_with_body(models.ScenarioProject, + 'project', + version.projects) @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 + version.projects = self._update_with_body(models.ScenarioProject, + 'project', + list()) @iter_installers @iter_versions @@ -257,12 +234,50 @@ class ScenarioUpdater(object): 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_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 _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_projects(self, projects): return self._filter('project', projects) @@ -602,3 +617,74 @@ class ScenarioOwnerHandler(GenericScenarioUpdateHandler): 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//versions? \ + installer= + @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//versions? \ + installer= + @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//versions? \ + installer= + @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}) diff --git a/utils/test/testapi/opnfv_testapi/router/url_mappings.py b/utils/test/testapi/opnfv_testapi/router/url_mappings.py index 9c9556c6b..bdfc70154 100644 --- a/utils/test/testapi/opnfv_testapi/router/url_mappings.py +++ b/utils/test/testapi/opnfv_testapi/router/url_mappings.py @@ -64,6 +64,8 @@ mappings = [ scenario_handlers.ScenarioProjectsHandler), (r"/api/v1/scenarios/([^/]+)/owner", scenario_handlers.ScenarioOwnerHandler), + (r"/api/v1/scenarios/([^/]+)/versions", + scenario_handlers.ScenarioVersionsHandler), # static path (r'/(.*\.(css|png|gif|js|html|json|map|woff2|woff|ttf))', diff --git a/utils/test/testapi/opnfv_testapi/tests/unit/resources/test_scenario.py b/utils/test/testapi/opnfv_testapi/tests/unit/resources/test_scenario.py index 50a8c8d2d..360b4fa89 100644 --- a/utils/test/testapi/opnfv_testapi/tests/unit/resources/test_scenario.py +++ b/utils/test/testapi/opnfv_testapi/tests/unit/resources/test_scenario.py @@ -175,6 +175,10 @@ class TestScenarioUpdate(TestScenarioBase): locator = 'installer={}&version={}'.format( self.installer, self.version) + elif item in ['versions']: + locator = 'installer={}'.format( + self.installer) + self.update_url = '{}/{}?{}'.format(self.scenario_url, item, locator) @@ -275,6 +279,15 @@ class TestScenarioUpdate(TestScenarioBase): scenario['installers'][0]['versions'][0]['projects'] = [update] return [update], scenario + @update_url_fixture('projects') + @update_partial('_update', '_conflict') + def test_updateProjects_duplicated(self, scenario): + update1 = models.ScenarioProject(project='qtip').format() + update2 = models.ScenarioProject(project='qtip').format() + scenario['installers'][0]['versions'][0]['projects'] = [update1, + update2] + return [update1, update2], scenario + @update_url_fixture('projects') @update_partial('_update', '_bad_request') def test_updateProjects_bad_schema(self, scenario): @@ -301,6 +314,61 @@ class TestScenarioUpdate(TestScenarioBase): scenario['installers'][0]['versions'][0]['owner'] = new_owner return update, scenario + @update_url_fixture('versions') + @update_partial('_add', '_success') + def test_addVersions_succ(self, scenario): + add = models.ScenarioVersion(version='Euphrates').format() + scenario['installers'][0]['versions'].append(add) + return [add], scenario + + @update_url_fixture('versions') + @update_partial('_add', '_conflict') + def test_addVersions_already_exist(self, scenario): + add = models.ScenarioVersion(version='master').format() + scenario['installers'][0]['versions'].append(add) + return [add], scenario + + @update_url_fixture('versions') + @update_partial('_add', '_bad_request') + def test_addVersions_bad_schema(self, scenario): + add = models.ScenarioVersion(version='euphrates').format() + add['notexist'] = None + scenario['installers'][0]['versions'].append(add) + return [add], scenario + + @update_url_fixture('versions') + @update_partial('_update', '_success') + def test_updateVersions_succ(self, scenario): + update = models.ScenarioVersion(version='euphrates').format() + scenario['installers'][0]['versions'] = [update] + return [update], scenario + + @update_url_fixture('versions') + @update_partial('_update', '_conflict') + def test_updateVersions_duplicated(self, scenario): + update1 = models.ScenarioVersion(version='euphrates').format() + update2 = models.ScenarioVersion(version='euphrates').format() + scenario['installers'][0]['versions'] = [update1, update2] + return [update1, update2], scenario + + @update_url_fixture('versions') + @update_partial('_update', '_bad_request') + def test_updateVersions_bad_schema(self, scenario): + update = models.ScenarioVersion(version='euphrates').format() + update['not_owner'] = 'Iam' + scenario['installers'][0]['versions'] = [update] + return [update], scenario + + @update_url_fixture('versions') + @update_partial('_delete', '_success') + def test_deleteVersions(self, scenario): + deletes = ['master'] + versions = scenario['installers'][0]['versions'] + scenario['installers'][0]['versions'] = filter( + lambda f: f['version'] != 'master', + versions) + return deletes, scenario + def _add(self, update_req, new_scenario): return self.post_direct_url(self.update_url, update_req)