diff options
9 files changed, 240 insertions, 16 deletions
diff --git a/testapi/opnfv_testapi/tests/UI/e2e/scenarioControllerSpec.js b/testapi/opnfv_testapi/tests/UI/e2e/scenarioControllerSpec.js index 60d4949..564fbcf 100644 --- a/testapi/opnfv_testapi/tests/UI/e2e/scenarioControllerSpec.js +++ b/testapi/opnfv_testapi/tests/UI/e2e/scenarioControllerSpec.js @@ -336,7 +336,7 @@ describe('testing the scenarios page for anonymous user', function () { }); -describe('testing the scenarios page for anonymous user', function () { +describe('testing the scenarios page for user', function () { beforeEach(function(){ mock([ { @@ -662,7 +662,7 @@ describe('testing the scenarios page for anonymous user', function () { browser.wait(EC.urlContains(baseURL+ '#/scenarios/test-scenario'), 10000); }); - it( 'should not show the add installer option for user', function() { + it( 'should show the add installer option for user', function() { browser.get(baseURL+"#/scenarios/test-scenario"); var EC = browser.ExpectedConditions; browser.wait(EC.urlContains(baseURL+ '#/scenarios/test-scenario'), 10000); @@ -1009,6 +1009,42 @@ describe('testing the scenarios page for anonymous user', function () { .isDisplayed()).toBe(true); }); + it( 'Add multiple Customs by user', function() { + browser.get(baseURL+"#/scenarios/test-scenario"); + var EC = browser.ExpectedConditions; + browser.wait(EC.urlContains(baseURL+ '#/scenarios/test-scenario'), 10000); + var installersShow = element(by.xpath('//*[@id="ng-app"]/body/div/div[1]/div/table/tbody/tr[5]/td[2]/div[1]/a/p')) + installersShow.click(); + var installerShow = element(by.xpath('//*[@id="ng-app"]/body/div/div[1]/div/table/tbody/tr[5]/td[2]/div[3]/div/table/tbody/tr[1]/td[2]/a')) + installerShow.click(); + var versionsShow = element(by.xpath('//*[@id="ng-app"]/body/div/div[1]/div/table/tbody/tr[5]/td[2]/div[3]/div/table/tbody/tr[2]/td[2]/div[1]/a/p')) + versionsShow.click(); + var versionShow = element(by.xpath('//*[@id="ng-app"]/body/div/div[1]/div/table/tbody/tr[5]/td[2]/div[3]/div/table/tbody/tr[2]/td[2]/div[3]/div/table/tbody/tr[1]/td[2]/a')) + versionShow.click() + var projectsShow = element(by.xpath('//*[@id="ng-app"]/body/div/div[1]/div/table/tbody/tr[5]/td[2]/div[3]/div/table/tbody/tr[2]/td[2]/div[3]/div/table/tbody/tr[3]/td[2]/div[1]/a')) + projectsShow.click(); + var projectShow = element(by.xpath('//*[@id="ng-app"]/body/div/div[1]/div/table/tbody/tr[5]/td[2]/div[3]/div/table/tbody/tr[2]/td[2]/div[3]/div/table/tbody/tr[3]/td[2]/div[3]/div/table/tbody/tr[1]/td[2]/a')) + projectShow.click(); + var customsShow = element(by.xpath('//*[@id="ng-app"]/body/div/div[1]/div/table/tbody/tr[5]/td[2]/div[3]/div/table/tbody/tr[2]/td[2]/div[3]/div/table/tbody/tr[3]/td[2]/div[3]/div/table/tbody[1]/tr[4]/td[2]/a/p')) + customsShow.click(); + var row = element.all(by.repeater('(indexCU, custom) in project.customs')).first(); + var cells = row.all(by.tagName('td')); + expect(cells.get(0).getText()).toContain("dvs"); + var buttonAdd = element(by.xpath('//*[@id="ng-app"]/body/div/div[1]/div/table/tbody/tr[5]/td[2]/div[3]/div/table/tbody/tr[2]/td[2]/div[3]/div/table/tbody/tr[3]/td[2]/div[3]/div/table/tbody[1]/tr[4]/td[2]/button')) + buttonAdd.click() + var custom = element(by.model('customModalCtrl.custom')); + browser.wait(EC.visibilityOf(custom), 5000); + custom.sendKeys('testC'); + // browser.pause(); + var buttonAddCustom = element(by.xpath('//*[@id="ng-app"]/body/div[3]/div/div/div/div[1]/div/fieldset/div/div/div/table/tfoot/tr/td[2]/input')) + buttonAddCustom.click(); + custom.sendKeys('testB'); + var buttonOk = element(by.xpath('//*[@id="ng-app"]/body/div[3]/div/div/div/div[2]/button[1]')) + buttonOk.click() + expect(element(by.cssContainingText(".alert","Customs are successfully updated.")) + .isDisplayed()).toBe(true); + }); + it( 'Delete Customs by user', function() { browser.get(baseURL+"#/scenarios/test-scenario"); var EC = browser.ExpectedConditions; diff --git a/testapi/opnfv_testapi/tests/unit/handlers/test_deploy_result.py b/testapi/opnfv_testapi/tests/unit/handlers/test_deploy_result.py index 65e765e..8f2ca76 100644 --- a/testapi/opnfv_testapi/tests/unit/handlers/test_deploy_result.py +++ b/testapi/opnfv_testapi/tests/unit/handlers/test_deploy_result.py @@ -92,6 +92,10 @@ class DeployResultGet(DeployResultBase): self.req_d_id = self._create_d() self.req_10d_later = self._create_changed_date(days=10) + @executor.get(httplib.OK, 'assert_res') + def test_getOne(self): + return self.req_d_id + @executor.query(httplib.OK, '_query_success', 3) def test_queryInstaller(self): return self._set_query('installer') @@ -165,6 +169,19 @@ class DeployResultGet(DeployResultBase): self._create_error_start_date('') return self._set_query(period=5) + @executor.query(httplib.OK, '_query_success', 0) + def test_notFound(self): + return self._set_query('installer', + 'version', + 'job_name', + 'build_id', + 'scenario', + 'upstream_job_name', + 'upstream_build_id', + 'criteria', + pod='notExistPod', + period=1) + def _query_success(self, body, number): self.assertEqual(number, len(body.deployresults)) diff --git a/testapi/opnfv_testapi/ui/components/pods/podsController.js b/testapi/opnfv_testapi/ui/components/pods/podsController.js index 95e3571..38e084d 100644 --- a/testapi/opnfv_testapi/ui/components/pods/podsController.js +++ b/testapi/opnfv_testapi/ui/components/pods/podsController.js @@ -137,7 +137,6 @@ function batchDelete(){ var index; var checkedBox = []; - console.log(ctrl.checkBox) for(index in ctrl.checkBox){ if(!ctrl.showError){ if(ctrl.checkBox[index]){ @@ -153,7 +152,13 @@ * message */ function openBatchDeleteModal() { - confirmModal("Delete",ctrl.batchDelete); + var deleteObjects = [] + for(var index in ctrl.checkBox){ + if(ctrl.checkBox[index]){ + deleteObjects.push(ctrl.data.pods[index].name) + } + } + confirmModal("Delete", 'pods', ctrl.batchDelete, deleteObjects); } /** @@ -162,7 +167,7 @@ */ function openDeleteModal(name) { console.log(name) - confirmModal("Delete", ctrl.podDelete, name); + confirmModal("Delete", 'pod', ctrl.podDelete, name); } /** diff --git a/testapi/opnfv_testapi/ui/components/scenarios/modals/customModal.html b/testapi/opnfv_testapi/ui/components/scenarios/modals/customModal.html index 987cb1e..90e4544 100644 --- a/testapi/opnfv_testapi/ui/components/scenarios/modals/customModal.html +++ b/testapi/opnfv_testapi/ui/components/scenarios/modals/customModal.html @@ -6,11 +6,31 @@ <legend>{{customModalCtrl.data.text}}</legend> <div class="row"> <div class="update-project"> - <label for="cpid" class="control-label col-sm-4">Custom: </label> - <div class="col-sm-6"> - <input type="text" class="form-control" ng-model="customModalCtrl.custom"/> - <p class="help-block"></p> - </div> + <label for="cpid" class="control-label col-sm-4">Custom: </label> + <table cellpadding="0" cellspacing="0"> + <tbody ng-repeat="custom in customModalCtrl.customs"> + <tr> + <td> + <div class="col-sm-12"> + <input type="text" class="form-control" value="{{custom}}" disabled/> + <p class="help-block"></p> + </div> + </td> + <td><input type="button" class="btn btn-danger" ng-click="customModalCtrl.remove($index)" value="Remove" /></td> + </tr> + </tbody> + <tfoot> + <tr> + <td> + <div class="col-sm-12"> + <input type="text" class="form-control" ng-model="customModalCtrl.custom"/> + <p class="help-block"></p> + </div> + </td> + <td><input type="button" class="btn btn-primary" ng-click="customModalCtrl.add()" value="Add" /></td> + </tr> + </tfoot> + </table> </div> </div> </div> diff --git a/testapi/opnfv_testapi/ui/components/scenarios/scenario/scenarioController.js b/testapi/opnfv_testapi/ui/components/scenarios/scenario/scenarioController.js index 53eb13a..b76f63c 100644 --- a/testapi/opnfv_testapi/ui/components/scenarios/scenario/scenarioController.js +++ b/testapi/opnfv_testapi/ui/components/scenarios/scenario/scenarioController.js @@ -435,15 +435,34 @@ ctrl.cancel = cancel; ctrl.data = angular.copy(data); ctrl.open = open; + ctrl.add = add; + ctrl.remove = remove; + ctrl.customs = []; + + function add() { + var custom = ctrl.custom; + if(custom!="" && custom!=undefined ){ + ctrl.customs.push(custom); + ctrl.custom = ""; + } + }; + + function remove(index) { + // var name = ctrl.customs[index].Name; + ctrl.customs.splice(index, 1); + + } /** * Initiate confirmation and call the success handler with the * inputs. */ function confirm() { - ctrl.customs = [] - ctrl.customs.push(ctrl.custom) + var custom = ctrl.custom; + if(custom!="" && custom!=undefined ){ + ctrl.customs.push(custom); + } ctrl.data.successHandler(ctrl.customs,ctrl.data.project,ctrl.data.version,ctrl.data.installer); $uibModalInstance.dismiss('cancel'); diff --git a/testapi/opnfv_testapi/ui/shared/alerts/confirmModal.html b/testapi/opnfv_testapi/ui/shared/alerts/confirmModal.html index e5397e0..417af37 100644 --- a/testapi/opnfv_testapi/ui/shared/alerts/confirmModal.html +++ b/testapi/opnfv_testapi/ui/shared/alerts/confirmModal.html @@ -10,7 +10,7 @@ </div> <div class="Delete" ng-class="{ 'hidden': confirmModal.data.text!='Delete' }"> <div class="form-group"> - <label for="confirmText"> You are about to delete.</label> + <label for="confirmText"> You are about to delete following {{confirmModal.data.resource}} : {{confirmModal.deleteObjects}} </label> <br> Do you want to proceed? </div> diff --git a/testapi/opnfv_testapi/ui/shared/alerts/confirmModalFactory.js b/testapi/opnfv_testapi/ui/shared/alerts/confirmModalFactory.js index 5e79775..c115a3c 100644 --- a/testapi/opnfv_testapi/ui/shared/alerts/confirmModalFactory.js +++ b/testapi/opnfv_testapi/ui/shared/alerts/confirmModalFactory.js @@ -11,17 +11,19 @@ * Opens confirm modal dialog with input textbox */ function confirmModal($uibModal) { - return function(text, successHandler, name) { + return function(text, resource, successHandler, name) { $uibModal.open({ - templateUrl: '/testapi-ui/shared/alerts/confirmModal.html', + templateUrl: 'testapi-ui/shared/alerts/confirmModal.html', controller: 'CustomConfirmModalController as confirmModal', size: 'md', resolve: { data: function () { return { text: text, + resource: resource, successHandler: successHandler, name: name + }; } } @@ -44,8 +46,26 @@ ctrl.confirm = confirm; ctrl.cancel = cancel; - + ctrl.buildDeleteObjects = buildDeleteObjects; ctrl.data = angular.copy(data); + + function buildDeleteObjects(){ + ctrl.deleteObjects = ''; + if (typeof ctrl.data.name === 'string') { + ctrl.deleteObjects = ctrl.data.name + } + else{ + for(var index in ctrl.data.name){ + if(index==0){ + ctrl.deleteObjects += ctrl.data.name[index] + } + else{ + ctrl.deleteObjects += ", "+ ctrl.data.name[index] + } + + } + } + } /** * Initiate confirmation and call the success handler with the * input text. @@ -63,5 +83,7 @@ function cancel() { $uibModalInstance.dismiss('cancel'); } + + ctrl.buildDeleteObjects(); } })(); diff --git a/testapi/testapi-client/setup.cfg b/testapi/testapi-client/setup.cfg index 1e25b73..8174720 100644 --- a/testapi/testapi-client/setup.cfg +++ b/testapi/testapi-client/setup.cfg @@ -25,6 +25,7 @@ testapi = project create = testapiclient.projects:ProjectCreate project get = testapiclient.projects:ProjectGet + project getone = testapiclient.projects:ProjectGetOne project delete = testapiclient.projects:ProjectDelete project put = testapiclient.projects:ProjectPut diff --git a/testapi/testapi-client/testapiclient/projects.py b/testapi/testapi-client/testapiclient/projects.py new file mode 100644 index 0000000..57def5d --- /dev/null +++ b/testapi/testapi-client/testapiclient/projects.py @@ -0,0 +1,104 @@ +import json +from user import User +from cliff.command import Command +from httpClient import HTTPClient +from authHandler import AuthHandler +from config import Config + + +class ProjectBase(Command): + projects_url = Config.config.get("api", "url") + "/projects" + + +class ProjectGet(ProjectBase): + + def get_parser(self, prog_name): + parser = super(ProjectGet, self).get_parser(prog_name) + parser.add_argument('-name', default='', help='Search projects by name') + return parser + + def take_action(self, parsed_args): + httpClient = HTTPClient.get_Instance() + url = ProjectGet.projects_url + if parsed_args.name: + url = url + "?name=" + parsed_args.name + projects = httpClient.get(url) + print projects + + +class ProjectGetOne(ProjectBase): + + def get_parser(self, prog_name): + parser = super(ProjectGetOne, self).get_parser(prog_name) + parser.add_argument('-name', default='', required=True, help='Search project by name') + return parser + + def take_action(self, parsed_args): + httpClient = HTTPClient.get_Instance() + url = ProjectGet.projects_url + "/" + parsed_args.name + project = httpClient.get(url) + print project + + +class ProjectCreate(ProjectBase): + + def get_parser(self, prog_name): + parser = super(ProjectCreate, self).get_parser(prog_name) + parser.add_argument('-u', type=str, help='Username for authentication') + parser.add_argument('-p', type=str, help='Password for authentication') + parser.add_argument('project', type=json.loads, help='Project create request format :{ "name": (required)"", "description": (optional)""}') + return parser + + def take_action(self, parsed_args): + httpClient = HTTPClient.get_Instance() + if(parsed_args.u and parsed_args.p): + response = AuthHandler.authenticate(parsed_args.u, parsed_args.p) + if "login" in response.text: + print "Authentication has failed. Please check your username and password." + return + response = httpClient.post(ProjectCreate.projects_url, User.session, parsed_args.project) + if response.status_code == 200: + print "Project has been successfully created!" + else: + print response.text + + +class ProjectDelete(ProjectBase): + + def get_parser(self, prog_name): + parser = super(ProjectDelete, self).get_parser(prog_name) + parser.add_argument('-u', type=str, help='Username for authentication') + parser.add_argument('-p', type=str, help='Password for authentication') + parser.add_argument('-name', type=str, required=True, help='Delete project by name') + return parser + + def take_action(self, parsed_args): + httpClient = HTTPClient.get_Instance() + if(parsed_args.u and parsed_args.p): + response = AuthHandler.authenticate(parsed_args.u, parsed_args.p) + if "login" in response.text: + print "Authentication has failed. Please check your username and password." + return + projects = httpClient.delete(ProjectDelete.projects_url + "/" + parsed_args.name, User.session) + print projects + + +class ProjectPut(ProjectBase): + + def get_parser(self, prog_name): + parser = super(ProjectPut, self).get_parser(prog_name) + parser.add_argument('-u', type=str, help='Username for authentication') + parser.add_argument('-p', type=str, help='Password for authentication') + parser.add_argument('-name', type=str, required=True, help='Update project by name') + parser.add_argument('project', type=json.loads, help='Project Update request format :{ "name": (required)"", "description": (optional)""}') + return parser + + def take_action(self, parsed_args): + httpClient = HTTPClient.get_Instance() + if(parsed_args.u and parsed_args.p): + response = AuthHandler.authenticate(parsed_args.u, parsed_args.p) + if "login" in response.text: + print "Authentication has failed. Please check your username and password." + return + projects = httpClient.put(ProjectPut.projects_url + "/" + parsed_args.name, User.session, parsed_args.project) + print projects |