diff options
Diffstat (limited to 'testapi/opnfv_testapi')
9 files changed, 89 insertions, 29 deletions
diff --git a/testapi/opnfv_testapi/common/check.py b/testapi/opnfv_testapi/common/check.py index 7f866dd..77b48f5 100644 --- a/testapi/opnfv_testapi/common/check.py +++ b/testapi/opnfv_testapi/common/check.py @@ -35,7 +35,7 @@ def is_authorized(method): if type(query) is not dict: query_data = query() else: - if self.json_args is None: + if self.json_args is None or 'name' not in self.json_args: query_data = query else: query_data = self.json_args @@ -47,13 +47,22 @@ def is_authorized(method): return wrapper -def is_allowed(method): +def is_reource_tied(method): @functools.wraps(method) def wrapper(self, *args, **kwargs): - if self.table == 'projects': - query_data = {} - query_data['project_name'] = kwargs.get('query')['name'] - data = yield dbapi.db_find_one('testcases', query_data) + query_data = {} + tied_map_tables = { + 'projects': ('testcases', 'project_name'), + 'pods': ('results', 'pod_name'), + 'testcases': ('results', 'case_name') + } + if self.table in tied_map_tables: + if method.__name__ == '_update': + if 'name' not in self.json_args: + ret = yield gen.coroutine(method)(self, *args, **kwargs) + raise gen.Return(ret) + query_data[tied_map_tables[self.table][1]] = kwargs.get('query')['name'] + data = yield dbapi.db_find_one(tied_map_tables[self.table][0], query_data) if data: raises.Unauthorized(message.tied_with_resource()) ret = yield gen.coroutine(method)(self, *args, **kwargs) diff --git a/testapi/opnfv_testapi/handlers/base_handlers.py b/testapi/opnfv_testapi/handlers/base_handlers.py index ed4aeb2..350c38d 100644 --- a/testapi/opnfv_testapi/handlers/base_handlers.py +++ b/testapi/opnfv_testapi/handlers/base_handlers.py @@ -179,7 +179,7 @@ class GenericApiHandler(web.RequestHandler): @gen.coroutine @check.not_exist @check.is_authorized - @check.is_allowed + @check.is_reource_tied def _delete(self, data, query=None): yield dbapi.db_delete(self.table, query) self.finish_request() @@ -190,7 +190,7 @@ class GenericApiHandler(web.RequestHandler): @check.not_exist @check.updated_one_not_exist @check.is_authorized - @check.is_allowed + @check.is_reource_tied def _update(self, data, query=None, **kwargs): data = self.table_cls.from_dict(data) update_req = self._update_requests(data) diff --git a/testapi/opnfv_testapi/tests/unit/handlers/test_pod.py b/testapi/opnfv_testapi/tests/unit/handlers/test_pod.py index d1eedc0..28d29b5 100644 --- a/testapi/opnfv_testapi/tests/unit/handlers/test_pod.py +++ b/testapi/opnfv_testapi/tests/unit/handlers/test_pod.py @@ -10,6 +10,7 @@ import httplib from opnfv_testapi.common import message from opnfv_testapi.models import pod_models as pm +from opnfv_testapi.models import result_models as rm from opnfv_testapi.tests.unit import executor from opnfv_testapi.tests.unit import fake_pymongo from opnfv_testapi.tests.unit.handlers import test_base as base @@ -23,6 +24,8 @@ class TestPodBase(base.TestBase): self.basePath = '/api/v1/pods' self.req_d = pm.PodCreateRequest.from_dict(self.pod_d.format()) self.req_e = pm.PodCreateRequest.from_dict(self.pod_e.format()) + self.results_d = rm.ResultCreateRequest.from_dict( + self.load_json('test_result')) def assert_get_body(self, pod, req=None): if not req: @@ -101,3 +104,37 @@ class TestPodGet(TestPodBase): self.assert_get_body(pod) else: self.assert_get_body(pod, self.req_e) + + +class TestPodDelete(TestPodBase): + @executor.mock_valid_lfid() + def setUp(self): + super(TestPodDelete, self).setUp() + fake_pymongo.pods.insert(self.pod_d.format()) + fake_pymongo.projects.insert({'name': self.results_d.project_name}) + fake_pymongo.testcases.insert({'name': self.results_d.case_name, + 'project_name': self.results_d.project_name}) + + @executor.delete(httplib.BAD_REQUEST, message.not_login()) + def test_notlogin(self): + return self.pod_d.name + + @executor.delete(httplib.NOT_FOUND, message.not_found_base) + def test_notFound(self): + return 'notFound' + + @executor.mock_valid_lfid() + @executor.delete(httplib.UNAUTHORIZED, message.tied_with_resource()) + def test_deleteNotAllowed(self): + self.create_help('/api/v1/results', self.results_d) + return self.pod_d.name + + @executor.mock_valid_lfid() + @executor.delete(httplib.OK, '_assert_delete') + def test_success(self): + return self.pod_d.name + + def _assert_delete(self, body): + self.assertEqual(body, '') + code, body = self.get(self.pod_d.name) + self.assertEqual(code, httplib.NOT_FOUND) diff --git a/testapi/opnfv_testapi/tests/unit/handlers/test_testcase.py b/testapi/opnfv_testapi/tests/unit/handlers/test_testcase.py index 9a2bf58..78f3ab1 100644 --- a/testapi/opnfv_testapi/tests/unit/handlers/test_testcase.py +++ b/testapi/opnfv_testapi/tests/unit/handlers/test_testcase.py @@ -10,6 +10,7 @@ import httplib from opnfv_testapi.common import message from opnfv_testapi.models import testcase_models as tcm +from opnfv_testapi.models import result_models as rm from opnfv_testapi.tests.unit import executor from opnfv_testapi.tests.unit import fake_pymongo from opnfv_testapi.tests.unit.handlers import test_base as base @@ -32,6 +33,8 @@ class TestCaseBase(base.TestBase): self.basePath = '/api/v1/projects/%s/cases' fake_pymongo.projects.insert(self.project_e.format()) print self.req_d.format() + self.results_d = rm.ResultCreateRequest.from_dict( + self.load_json('test_result')) def assert_body(self, case, req=None): if not req: @@ -176,11 +179,20 @@ class TestCaseDelete(TestCaseBase): def setUp(self): super(TestCaseDelete, self).setUp() self.create_d() + fake_pymongo.pods.insert(self.pod_d.format()) + fake_pymongo.projects.insert({'name': self.results_d.project_name}) + fake_pymongo.testcases.insert({'name': self.results_d.case_name, + 'project_name': self.results_d.project_name}) @executor.delete(httplib.NOT_FOUND, message.not_found_base) def test_notFound(self): return 'notFound' + @executor.delete(httplib.UNAUTHORIZED, message.tied_with_resource()) + def test_deleteNotAllowed(self): + print self.create_help('/api/v1/results', self.results_d) + return self.results_d.case_name + @executor.delete(httplib.OK, '_delete_success') def test_success(self): return self.req_d.name diff --git a/testapi/opnfv_testapi/ui/app.js b/testapi/opnfv_testapi/ui/app.js index ae50166..def88d2 100644 --- a/testapi/opnfv_testapi/ui/app.js +++ b/testapi/opnfv_testapi/ui/app.js @@ -42,6 +42,21 @@ }; }]); + angular + .module('testapiApp') + .directive('ngEnter', function () { + return function (scope, element, attrs) { + element.bind("keydown keypress", function (event) { + if(event.which === 13) { + scope.$apply(function (){ + scope.$eval(attrs.ngEnter); + }); + event.preventDefault(); + } + }); + }; + }); + configureRoutes.$inject = ['$stateProvider', '$urlRouterProvider']; /** diff --git a/testapi/opnfv_testapi/ui/components/deploy-results/deployResults.html b/testapi/opnfv_testapi/ui/components/deploy-results/deployResults.html index 6fbaaea..380416f 100644 --- a/testapi/opnfv_testapi/ui/components/deploy-results/deployResults.html +++ b/testapi/opnfv_testapi/ui/components/deploy-results/deployResults.html @@ -15,7 +15,7 @@ <div class="col-sm-2 pull-right" ng-class="{'hidden': ctrl.filter=='start_date' || ctrl.filter=='end_date'}"> <span style="margin-top:6px">Search: </span> <input list="filter" name="filter" class="form-control search" style="display:inline;width:105px;padding-left:6px;" - ng-Model="ctrl.filterText" placeholder="Search String"> + ng-enter="ctrl.filterList()" ng-Model="ctrl.filterText" placeholder="Search String"> <datalist id="filter" ng-class="{ 'hidden' : ctrl.filterOption.length<0}"> <option ng-repeat="(index, filterValue) in ctrl.filterOption " value="{{filterValue}}">{{filterValue}}</option> </datalist> @@ -24,6 +24,7 @@ <span style="margin-top:6px">Start Date: </span> <p class="input-group" style="width:48%;display:inline-flex;"> <input type="text" class="form-control" + ng-enter="ctrl.filterList()" uib-datepicker-popup="{{ctrl.format}}" ng-model="ctrl.filterText" is-open="ctrl.startOpen" close-text="Close" /> @@ -38,6 +39,7 @@ <span style="margin-top:6px">End Date: </span> <p class="input-group" style="width:48%;display:inline-flex;"> <input type="text" class="form-control" + ng-enter="ctrl.filterList()" uib-datepicker-popup="{{ctrl.format}}" ng-model="ctrl.filterText" is-open="ctrl.endOpen" close-text="Close" /> diff --git a/testapi/opnfv_testapi/ui/components/pods/pods.html b/testapi/opnfv_testapi/ui/components/pods/pods.html index 7873977..8e66a9c 100644 --- a/testapi/opnfv_testapi/ui/components/pods/pods.html +++ b/testapi/opnfv_testapi/ui/components/pods/pods.html @@ -22,7 +22,7 @@ </div> <div class="col-sm-3 pull-right"> <span style="margin-top:6px">Search: </span> - <input type="text" class="form-control search" ng-Model="ctrl.filterText" placeholder="Search String"> + <input type="text" class="form-control search" ng-enter="ctrl.listPods()" ng-Model="ctrl.filterText" placeholder="Search String"> </div> </div> <div class="col-md-12"> diff --git a/testapi/opnfv_testapi/ui/components/projects/projects.html b/testapi/opnfv_testapi/ui/components/projects/projects.html index b6b73d4..84902f8 100644 --- a/testapi/opnfv_testapi/ui/components/projects/projects.html +++ b/testapi/opnfv_testapi/ui/components/projects/projects.html @@ -18,7 +18,7 @@ </div> <div class="col-sm-3 pull-right"> <span style="margin-top:6px">Search: </span> - <input type="text" class="form-control search" ng-Model="ctrl.filterText" style="width:80%;" placeholder="Search By Name"> + <input type="text" class="form-control search" ng-enter="ctrl.listProjects()" ng-Model="ctrl.filterText" style="width:80%;" placeholder="Search By Name"> </div> </div> <div class='clo-md-12'> diff --git a/testapi/opnfv_testapi/ui/components/results/results.html b/testapi/opnfv_testapi/ui/components/results/results.html index 2756bb0..e1413d5 100644 --- a/testapi/opnfv_testapi/ui/components/results/results.html +++ b/testapi/opnfv_testapi/ui/components/results/results.html @@ -1,22 +1,5 @@ <h3>{{ctrl.pageHeader}}</h3> <p>{{ctrl.pageParagraph}}</p> -<form class="form-inline" ng-show="ctrl.isUserResults"> -<h4>Upload Results</h4> -<div class="form-group col-m-3"> - <input class="form-contrl btn btn-default" type = "file" file-model = "resultFile"/> -</div> -<div class="checkbox col-m-1"> - <label> - <input type="checkbox" ng-model="ctrl.isPublic">public - </label> -</div> -<div class="form-group col-m-3"> - <button class="btn btn-primary" ng-click = "ctrl.uploadFile()">upload result</button> -</div> -<div> -<lable>{{ctrl.uploadState}}</label> -</div> -</form> <div class="row" style="margin-bottom:24px;"></div> <div class="result-filters" style="border-top: none;"> <div class="row podTable" style="vertical-align:middle"> @@ -31,7 +14,7 @@ </div> <div class="col-sm-2 pull-right" ng-class="{'hidden': ctrl.filter=='start_date' || ctrl.filter=='end_date'}"> <span style="margin-top:6px">Search: </span> - <input list="filter" name="filter" class="form-control search" style="display:inline;width:105px;padding-left:6px;" + <input list="filter" ng-enter="ctrl.filterList()" name="filter" class="form-control search" style="display:inline;width:105px;padding-left:6px;" ng-Model="ctrl.filterText" placeholder="Search String"> <datalist id="filter" ng-class="{ 'hidden' : ctrl.filterOption.length<0}"> <option ng-repeat="(index, filterValue) in ctrl.filterOption " value="{{filterValue}}">{{filterValue}}</option> @@ -41,6 +24,7 @@ <span style="margin-top:6px">Start Date: </span> <p class="input-group" style="width:48%;display:inline-flex;"> <input type="text" class="form-control" + ng-enter="ctrl.filterList()" uib-datepicker-popup="{{ctrl.format}}" ng-model="ctrl.filterText" is-open="ctrl.startOpen" close-text="Close" /> @@ -55,6 +39,7 @@ <span style="margin-top:6px">End Date: </span> <p class="input-group" style="width:48%;display:inline-flex;"> <input type="text" class="form-control" + ng-enter="ctrl.filterList()" uib-datepicker-popup="{{ctrl.format}}" ng-model="ctrl.filterText" is-open="ctrl.endOpen" close-text="Close" /> |