diff options
26 files changed, 1147 insertions, 622 deletions
diff --git a/ci/htmlize/htmlize.py b/ci/htmlize/htmlize.py index da6a6cf..135d401 100644 --- a/ci/htmlize/htmlize.py +++ b/ci/htmlize/htmlize.py @@ -15,9 +15,9 @@ def main(args): # Merging two specs api_response = requests.get(args.api_declaration_url) - api_response = json.loads(api_response.content) + api_response = api_response.json() resource_response = requests.get(args.resource_listing_url) - resource_response = json.loads(resource_response.content) + resource_response = resource_response.json() resource_response['models'] = api_response['models'] resource_response['apis'] = api_response['apis'] @@ -41,7 +41,7 @@ if __name__ == '__main__': type=str, required=False, default=('http://testresults.opnfv.org' - '/test/swagger/resources.json'), + '/test/swagger/models.json'), help='Resource Listing Spec File') parser.add_argument('-au', '--api-declaration-url', type=str, diff --git a/testapi/3rd_party/static/testapi-ui/assets/css/style.css b/testapi/3rd_party/static/testapi-ui/assets/css/style.css index feed1b6..fb21399 100644 --- a/testapi/3rd_party/static/testapi-ui/assets/css/style.css +++ b/testapi/3rd_party/static/testapi-ui/assets/css/style.css @@ -281,3 +281,15 @@ a.glyphicon { border-top:none!important; padding-bottom:0px!important; } + +json-tree .key { + color: black!important; +} + +.branch-preview { + display: none!important; +} + +json-tree .leaf-value{ + word-break: normal!important; +}
\ No newline at end of file diff --git a/testapi/3rd_party/static/testapi-ui/assets/lib/angular-json-tree/angular-json-tree.css b/testapi/3rd_party/static/testapi-ui/assets/lib/angular-json-tree/angular-json-tree.css new file mode 100644 index 0000000..f25142a --- /dev/null +++ b/testapi/3rd_party/static/testapi-ui/assets/lib/angular-json-tree/angular-json-tree.css @@ -0,0 +1,76 @@ +/* Structure */ +json-tree { + box-sizing: border-box; +} +json-tree *, +json-tree *:before, +json-tree *:after { + box-sizing: border-box; +} +json-tree .key { + vertical-align: middle; +} +json-tree .expandable { + position: relative; + padding-left: 0px +} +json-tree .expandable::before { + pointer-events: none; +} +json-tree .branch-preview { + display: inline-block; + vertical-align: middle; +} +/* Looks */ +json-tree ul { + padding-left: 0px; + margin-bottom: 0px; +} +json-tree li, +json-tree ul { + list-style: none; +} +json-tree li { + line-height: 1.5em; +} +json-tree .key { + font-weight: bold; + color: #D02828; + /* padding: 5px 10px 5px 15px; */ +} +json-tree .key::after { + content: ':'; +} +json-tree json-node.expandable::before { + /* content: '\25b6'; */ + position: absolute; + left: 0px; + font-size: 10px; + -webkit-transition: -webkit-transform .1s ease; + transition: -webkit-transform .1s ease; + transition: transform .1s ease; + transition: transform .1s ease, -webkit-transform .1s ease; +} +json-tree json-node.expandable.expanded::before { + -webkit-transform: rotate(90deg); + transform: rotate(90deg); +} +json-tree .leaf-value, +json-tree .branch-preview { + word-break: break-all; +} +json-tree .branch-preview { + overflow: hidden; + font-style: italic; + max-width: 40%; + height: 1.5em; + opacity: .7; +} + +json-tree .firstkey::after { + content: ''; +} + +li > json-node > ul { + padding-left: 10px; +}
\ No newline at end of file diff --git a/testapi/3rd_party/static/testapi-ui/assets/lib/angular-json-tree/angular-json-tree.min.js b/testapi/3rd_party/static/testapi-ui/assets/lib/angular-json-tree/angular-json-tree.min.js new file mode 100644 index 0000000..97f407e --- /dev/null +++ b/testapi/3rd_party/static/testapi-ui/assets/lib/angular-json-tree/angular-json-tree.min.js @@ -0,0 +1,67 @@ +/*global angular */ ! function () { + "use strict"; + var e = { + is: function (e, a) { + return Object.prototype.toString.call(e).slice(8, -1) === a + }, + whatClass: function (e) { + return Object.prototype.toString.call(e).slice(8, -1) + }, + forKeys: function (e, a) { + for (var n in e) + if (e.hasOwnProperty(n) && "function" != typeof e[n] && a(n, e[n])) break + } + }; + angular.module("angular-json-tree", ["ajs.RecursiveDirectiveHelper"]).directive("jsonTree", [function () { + return { + restrict: "E", + scope: { + object: "=", + startExpanded: "&?", + rootName: "&?" + }, + template: '<json-node key="rootName() || \'\'" value="object" start-expanded="startExpanded()"></json-node>' + } + }]).directive("jsonNode", ["ajsRecursiveDirectiveHelper", function (a) { + return { + restrict: "E", + scope: { + key: "=", + value: "=", + startExpanded: "&?" + }, + compile: function (e) { + return a.compile(e, this) + }, + template: ' <span style="padding-left:0px" class= "key col-md-1" ng-class="{\'hidden\' : key==\'\' && key!=\'0\'}" ng-click="toggleExpanded()">{{key}}</span> <span class="leaf-value col-md-11" ng-if="!isExpandable">{{value}}</span> <span class="branch-preview" ng-if="isExpandable" ng-show="!isExpanded" ng-click="toggleExpanded()">{{preview}}</span> <ul class="branch-value" ng-if="isExpandable" > <li ng-repeat="(subkey,subval) in value"> <json-node key="subkey" class="col-md-12" value="subval"></json-node> </li> </ul>', + pre: function (a, n, s) { + if (n.addClass(e.whatClass(a.value).toLowerCase()), e.is(a.value, "Object") || e.is(a.value, "Array")) { + a.isExpandable = !0, n.addClass("expandable"); + var t = e.is(a.value, "Array"); + a.preview = t ? "[ " : "{ ", e.forKeys(a.value, function (e, n) { + t ? a.preview += n + ", " : a.preview += e + ": " + n + ", " + }), a.preview = a.preview.substring(0, a.preview.length - (a.preview.length > 2 ? 2 : 0)) + (t ? " ]" : " }"), a.startExpanded && a.startExpanded() && (a.shouldRender = !0, n.addClass("expanded")), a.isExpanded = a.startExpanded ? a.startExpanded() : !1, a.toggleExpanded = function () { + a.isExpanded = !a.isExpanded, a.isExpanded ? n.addClass("expanded") : n.removeClass("expanded"), a.shouldRender = !0 + } + } else a.isExpandable = !1, n.addClass("not-expandable") + } + } + }]), angular.module("ajs.RecursiveDirectiveHelper", []).factory("ajsRecursiveDirectiveHelper", ["$compile", function (e) { + return { + compile: function (a, n) { + angular.isFunction(n) && (n = { + post: n + }); + var s, t = a.contents().remove(); + return { + pre: n && n.pre ? n.pre : null, + post: function (a, r) { + s || (s = e(t)), s(a, function (e) { + r.append(e) + }), n && n.post && n.post.apply(null, arguments) + } + } + } + } + }]) +}();
\ No newline at end of file diff --git a/testapi/opnfv_testapi/handlers/result_handlers.py b/testapi/opnfv_testapi/handlers/result_handlers.py index 74acb2e..edcac6e 100644 --- a/testapi/opnfv_testapi/handlers/result_handlers.py +++ b/testapi/opnfv_testapi/handlers/result_handlers.py @@ -48,8 +48,6 @@ class GenericResultHandler(base_handlers.GenericApiHandler): period = datetime.now() - timedelta(days=v) obj = {"$gte": str(period)} query['start_date'] = obj - elif k == 'trust_indicator': - query[k + '.current'] = float(v) elif k == 'from': date_range.update({'$gte': str(v)}) elif k == 'to': @@ -108,8 +106,6 @@ class ResultsCLHandler(GenericResultHandler): - to : ending time in 2016-01-01 or 2016-01-01 00:01:23 - scenario : the test scenario (previously version) - 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 GET /results/project=functest&case=vPing&version=Arno-R1 \ &pod=pod_name&period=15 @@ -168,10 +164,6 @@ class ResultsCLHandler(GenericResultHandler): @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 descend: true, newest2oldest; false, oldest2newest @type descend: L{string} @in descend: query @@ -228,19 +220,3 @@ class ResultsGURHandler(GenericResultHandler): query = dict() query["_id"] = objectid.ObjectId(result_id) self._get_one(query=query) - - @swagger.operation(nickname="updateTestResultById") - def put(self, result_id): - """ - @description: update a single result by _id - @param body: fields to be updated - @type body: L{ResultUpdateRequest} - @in body: body - @rtype: L{Result} - @return 200: update success - @raise 404: result not exist - @raise 403: nothing to update - """ - query = {'_id': objectid.ObjectId(result_id)} - db_keys = [] - self._update(query=query, db_keys=db_keys) diff --git a/testapi/opnfv_testapi/models/result_models.py b/testapi/opnfv_testapi/models/result_models.py index f8379d8..602318a 100644 --- a/testapi/opnfv_testapi/models/result_models.py +++ b/testapi/opnfv_testapi/models/result_models.py @@ -11,45 +11,7 @@ from opnfv_testapi.tornado_swagger import swagger @swagger.model() -class TIHistory(base_models.ModelBase): - """ - @ptype step: L{float} - """ - def __init__(self, date=None, step=0): - self.date = date - self.step = step - - -@swagger.model() -class TI(base_models.ModelBase): - """ - @property histories: trust_indicator update histories - @ptype histories: C{list} of L{TIHistory} - @ptype current: L{float} - """ - def __init__(self, current=0): - self.current = current - self.histories = list() - - def __eq__(self, other): - return (self.current == other.current and self._histories_eq(other)) - - def _histories_eq(self, other): - hs_equal = all(self.histories[i] == other.histories[i] - for i in range(len(self.histories))) - return len(self.histories) == len(other.histories) and hs_equal - - @staticmethod - def attr_parser(): - return {'histories': TIHistory} - - -@swagger.model() class ResultCreateRequest(base_models.ModelBase): - """ - @property trust_indicator: - @ptype trust_indicator: L{TI} - """ def __init__(self, pod_name=None, project_name=None, @@ -61,8 +23,7 @@ class ResultCreateRequest(base_models.ModelBase): details=None, build_tag=None, scenario=None, - criteria=None, - trust_indicator=None): + criteria=None): self.pod_name = pod_name self.project_name = project_name self.case_name = case_name @@ -74,35 +35,15 @@ class ResultCreateRequest(base_models.ModelBase): self.build_tag = build_tag self.scenario = scenario self.criteria = criteria - self.trust_indicator = trust_indicator if trust_indicator else TI(0) def __eq__(self, other): - simple_equal = all(getattr(self, k) == getattr(other, k) - for k in self.format().keys() - if k not in ['_id', 'trust_indicator']) - return simple_equal and self.trust_indicator == other.trust_indicator - - @staticmethod - def attr_parser(): - return {'trust_indicator': TI} - - -@swagger.model() -class ResultUpdateRequest(base_models.ModelBase): - """ - @property trust_indicator: - @ptype trust_indicator: L{TI} - """ - def __init__(self, trust_indicator=None): - self.trust_indicator = trust_indicator + return all(getattr(self, k) == getattr(other, k) + for k in self.format().keys() + if k not in ['_id']) @swagger.model() class TestResult(ResultCreateRequest): - """ - @property trust_indicator: used for long duration test case - @ptype trust_indicator: L{TI} - """ def __init__(self, _id=None, **kwargs): super(TestResult, self).__init__(**kwargs) self._id = _id diff --git a/testapi/opnfv_testapi/tests/UI/e2e/authenticateFalseSpec.js b/testapi/opnfv_testapi/tests/UI/e2e/authenticateFalseSpec.js index 3212b86..e287f29 100644 --- a/testapi/opnfv_testapi/tests/UI/e2e/authenticateFalseSpec.js +++ b/testapi/opnfv_testapi/tests/UI/e2e/authenticateFalseSpec.js @@ -47,7 +47,7 @@ describe('testing the pods page for anonymous user', function () { }); }); -describe('testing the pods page for anonymous user', function () { +describe('testing the project page for anonymous user', function () { beforeEach(function(){ mock([ { @@ -383,3 +383,158 @@ describe('testing the scenarios page for anonymous user', function () { }); +describe('testing the testCases page for anonymous user', function () { + beforeEach(function(){ + mock([ + { + request: { + path: '/api/v1/projects', + method: 'GET' + }, + response: { + data: { + "projects": [ + { + "creator": "thuva4", + "_id": "5a0c022f9a07c846d3c2cc94", + "creation_date": "2017-11-15 14:30:31.200259", + "description": "dsfsd", + "name": "testproject" + } + ] + } + } + }, + { + request: { + path: '/api/v1/projects/testproject', + method: 'GET' + }, + response: { + data: { + "creator": "thuva4", + "_id": "5a0c022f9a07c846d3c2cc94", + "creation_date": "2017-11-15 14:30:31.200259", + "description": "dsfsd", + "name": "testproject" + } + } + }, + { + request: { + path: '/api/v1/projects/testproject/cases', + method: 'GET' + }, + response: { + data: { + "testcases": [ + { + "project_name": "testproject", + "run": null, + "description": null, + "tags": null, + "creation_date": "2017-12-20 18:47:04.025544", + "dependencies": null, + "tier": null, + "trust": null, + "blocking": null, + "name": "testCase", + "ci_loop": null, + "url": null, + "version": null, + "criteria": null, + "domains": null, + "_id": "5a3a62d09a07c836e06858fb", + "catalog_description": null + } + ] + } + } + }, + { + request: { + path: '/api/v1/projects/testproject/cases/testCase', + method: 'GET' + }, + response: { + data: { + "project_name": "testproject", + "run": null, + "description": null, + "tags": null, + "creation_date": "2017-12-20 18:47:04.025544", + "dependencies": null, + "tier": null, + "trust": null, + "blocking": null, + "name": "testCase", + "ci_loop": null, + "url": null, + "version": null, + "criteria": null, + "domains": null, + "_id": "5a3a62d09a07c836e06858fb", + "catalog_description": null + } + } + } + ]); + }); + + afterEach(function(){ + mock.teardown(); + }); + + it( 'should show the testCases for anonymous user', function() { + browser.get(baseURL+"#/projects/testproject"); + var testCases = element(by.linkText('Test Cases')); + testCases.click(); + var row = element.all(by.repeater('(index, testcase) in testCasesCtrl.data.testcases')).first(); + var cells = row.all(by.tagName('td')); + expect(cells.get(1).getText()).toContain("testCase"); + }); + + it( 'navigate anonymous user to testCase page', function() { + browser.get(baseURL+"#/projects/testproject"); + var testCases = element(by.linkText('Test Cases')); + testCases.click(); + var testCase = element(by.linkText('testCase')); + testCase.click(); + var EC = browser.ExpectedConditions; + browser.wait(EC.urlContains(baseURL+ '#/projects/testproject/testCase'), 10000); + }); + + it('create button is visible for anonymous user ', function () { + browser.get(baseURL+"#/projects/testproject"); + var testCases = element(by.linkText('Test Cases')); + testCases.click(); + var buttonCreate = element(by.buttonText('Create')); + expect(buttonCreate.isDisplayed()).toBe(true); + }); + + it('Delete button is not visible for anonymous user ', function () { + browser.get(baseURL+"#/projects/testproject"); + var testCases = element(by.linkText('Test Cases')); + testCases.click(); + var buttonDelete = element(by.buttonText('Delete')); + expect(buttonDelete.isDisplayed()).toBe(true); + }); + + it('delete Operation is visible for anonymous user ', function () { + browser.get(baseURL+"#/projects/testproject"); + var testCases = element(by.linkText('Test Cases')); + testCases.click(); + var deleteOperation = element(by.css('a[title=Delete]')); + expect(deleteOperation.isDisplayed()).toBe(true); + }); + + it('Edit Operation is visible for anonymous user ', function () { + browser.get(baseURL+"#/projects/testproject"); + var testCases = element(by.linkText('Test Cases')); + testCases.click(); + var editOperation = element(by.css('a[title=Edit]')); + expect(editOperation.isDisplayed()).toBe(true); + }); +}); + + diff --git a/testapi/opnfv_testapi/tests/UI/e2e/projectsControllerSpec.js b/testapi/opnfv_testapi/tests/UI/e2e/projectsControllerSpec.js index ed5fe9f..1117ef5 100644 --- a/testapi/opnfv_testapi/tests/UI/e2e/projectsControllerSpec.js +++ b/testapi/opnfv_testapi/tests/UI/e2e/projectsControllerSpec.js @@ -63,12 +63,6 @@ describe('testing the Projects Link for anonymous user', function () { expect(cells.get(1).getText()).toContain("testproject"); }); - // it('redirect to project page when user clicks a project',function(){ - // var projectlink = element(by.linkText('testproject')).click(); - // var EC = browser.ExpectedConditions; - // browser.wait(EC.urlContains(baseURL+ '/#/projects/testproject'), 10000); - // }); - it('delete Operation is not visible for anonymous user ', function () { browser.get(baseURL+'#/projects'); var deleteOperation = element(by.css('a[title=Delete]')); @@ -158,10 +152,10 @@ describe('testing the Project Link for user who is not in submitter group', func expect(buttonCreate.isDisplayed()).toBeFalsy(); }); - it('Delete button is not visible for user ', function () { + it('Delete button is not visible for user ', function () { browser.get(baseURL+'#/projects'); - var buttonCreate = element(by.buttonText('Create')); - expect(buttonCreate.isDisplayed()).toBeFalsy(); + var buttonDelete = element(by.buttonText('Delete')); + expect(buttonDelete.isDisplayed()).toBeFalsy(); }); it('delete Operation is not visible for user ', function () { @@ -302,13 +296,13 @@ describe('testing the Project Link for user who is in submitter group', function expect(buttonCreate.isDisplayed()).toBe(true); }); - it('Delete button is not visible for anonymous user ', function () { + it('Delete button is visible for user ', function () { browser.get(baseURL+'#/projects'); - var buttonCreate = element(by.buttonText('Create')); - expect(buttonCreate.isDisplayed()).toBe(true); + var buttonDelete = element(by.buttonText('Delete')); + expect(buttonDelete.isDisplayed()).toBe(true); }); - it('delete Operation is not visible for user ', function () { + it('delete Operation is visible for user ', function () { browser.get(baseURL+'#/projects'); var deleteOperation = element(by.css('a[title=Delete]')); expect(deleteOperation.isDisplayed()).toBe(true); diff --git a/testapi/opnfv_testapi/tests/UI/e2e/resultsControllerSpec.js b/testapi/opnfv_testapi/tests/UI/e2e/resultsControllerSpec.js index 132f77d..925e82c 100644 --- a/testapi/opnfv_testapi/tests/UI/e2e/resultsControllerSpec.js +++ b/testapi/opnfv_testapi/tests/UI/e2e/resultsControllerSpec.js @@ -30,7 +30,6 @@ describe('testing the result page for anonymous user', function () { "user": null, "installer": "fuel", "scenario": "test-scenario", - "trust_indicator": null, "public": "true", "version": "euphrates", "details": "", @@ -45,11 +44,40 @@ describe('testing the result page for anonymous user', function () { }, { request: { + path: '/api/v1/results/5a45170bbb2092000e2643f4', + method: 'GET', + }, + response: { + data: { + "project_name": "testproject", + "description": "Demo results", + "stop_date": "2017-12-28 16:08:43", + "case_name": "testcase", + "build_tag": null, + "user": null, + "installer": "fuel", + "scenario": "test-scenario", + "public": "true", + "version": "euphrates", + "details": { + "failures": 0, + "errors": 0, + "stream": "steam text" + }, + "criteria": "PASS", + "_id": "5a45170bbb2092000e2643f4", + "start_date": "2017-12-28 14:44:27", + "pod_name": "testPod" + } + } + }, + { + request: { path: '/api/v1/results', method: 'GET', queryString: { page: '1', - project: 'testproject' + installer: 'testinstaller' } }, response: { @@ -66,7 +94,7 @@ describe('testing the result page for anonymous user', function () { "case_name": "testcase", "build_tag": null, "user": null, - "installer": "fuel", + "installer": "testinstaller", "scenario": "test-scenario", "trust_indicator": null, "public": "true", @@ -87,8 +115,8 @@ describe('testing the result page for anonymous user', function () { method: 'GET', queryString: { page: '1', - project: 'testproject', - case: 'testcase' + installer: 'testinstaller', + version: 'testversion' } }, response: { @@ -105,11 +133,10 @@ describe('testing the result page for anonymous user', function () { "case_name": "testcase", "build_tag": null, "user": null, - "installer": "fuel", + "installer": "testinstaller", "scenario": "test-scenario", - "trust_indicator": null, "public": "true", - "version": "euphrates", + "version": "testversion", "details": "", "criteria": "PASS", "_id": "5a45170bbb2092000e2643f6", @@ -119,7 +146,25 @@ describe('testing the result page for anonymous user', function () { ] } } - } + }, + { + request: { + path: '/api/v1/pods', + method: 'GET' + }, + response: { + data: { + pods: [ + {role: "community-ci", name: "test2", creator: "testUser", + details: "DemoDetails", mode: "metal", _id: "59f02f099a07c84bfc5c7ae5", + creation_date: "2017-10-25 11:58:25.926168"}, + {role: "production-ci", name: "test", creator: "testUser", + details: "DemoDetails", mode: "virtual", _id: "59f02f099a07c84bfc5c7aed", + creation_date: "2017-10-25 11:58:25.926168"} + ] + } + } + } ]); }); @@ -127,7 +172,7 @@ describe('testing the result page for anonymous user', function () { mock.teardown(); }); - it( 'should show the results page for anonymous user', function() { + it( 'should show the results page ', function() { browser.get(baseURL+"#/results"); expect(element(by.cssContainingText(".ng-binding.ng-scope","Test Results")).isDisplayed()).toBe(true); }); @@ -139,26 +184,37 @@ describe('testing the result page for anonymous user', function () { browser.wait(EC.urlContains(baseURL+ '#/results'), 10000); }); - it('Should show the results in results page for anonymous user ', function () { + it('Should show the results in results page', function () { browser.get(baseURL+"#/results"); var row = element.all(by.repeater('(index, result) in ctrl.data.results')).first(); var cells = row.all(by.tagName('td')); expect(cells.get(0).getText()).toContain("0e2643f4"); }); - it('Should show the results in results page related to the filters for anonymous user ', function () { + it( 'navigate to result page and check details', function() { + browser.get(baseURL); + var resultLink = element(by.linkText('Results')).click(); + var EC = browser.ExpectedConditions; + browser.wait(EC.urlContains(baseURL+ '#/results'), 10000); + var resultLink = element(by.linkText('0e2643f4')).click(); + browser.wait(EC.urlContains(baseURL+ '#/result/5a45170bbb2092000e2643f4'), 10000); + expect(element(by.cssContainingText(".key.col-md-1","failures")).isDisplayed()).toBe(true); + expect(element(by.cssContainingText(".leaf-value.col-md-11","0")).isDisplayed()).toBe(true); + }); + + it('Should show the results in results page related to the filters', function () { browser.get(baseURL+"#/results"); var filter = element(by.model('ctrl.filter')); var filterText = element(by.model('ctrl.filterText')); - filter.sendKeys('project'); - filterText.sendKeys('testproject'); + filter.sendKeys('installer'); + filterText.sendKeys('testinstaller'); var buttonFilter = element(by.buttonText('Filter')); buttonFilter.click(); var row = element.all(by.repeater('(index, result) in ctrl.data.results')).first(); var cells = row.all(by.tagName('td')); expect(cells.get(0).getText()).toContain("0e2643f5"); - filter.sendKeys('case'); - filterText.sendKeys('testcase') + filter.sendKeys('version'); + filterText.sendKeys('testversion') buttonFilter.click(); expect(cells.get(0).getText()).toContain("0e2643f6"); }); @@ -166,8 +222,8 @@ describe('testing the result page for anonymous user', function () { browser.get(baseURL+"#/results"); var filter = element(by.model('ctrl.filter')); var filterText = element(by.model('ctrl.filterText')); - filter.sendKeys('project'); - filterText.sendKeys('testproject1'); + filter.sendKeys('installer'); + filterText.sendKeys('testisntaller1'); var buttonFilter = element(by.buttonText('Filter')); buttonFilter.click(); expect(element(by.css('.alert.alert-danger.ng-binding.ng-scope')) @@ -235,7 +291,7 @@ describe('testing the result page for user', function () { method: 'GET', queryString: { page: '1', - project: 'testproject' + installer: 'testinstaller' } }, response: { @@ -252,9 +308,8 @@ describe('testing the result page for user', function () { "case_name": "testcase", "build_tag": null, "user": null, - "installer": "fuel", + "installer": "testinstaller", "scenario": "test-scenario", - "trust_indicator": null, "public": "true", "version": "euphrates", "details": "", @@ -273,8 +328,8 @@ describe('testing the result page for user', function () { method: 'GET', queryString: { page: '1', - project: 'testproject', - case: 'testcase' + installer: 'testinstaller', + version: 'testversion' } }, response: { @@ -291,11 +346,11 @@ describe('testing the result page for user', function () { "case_name": "testcase", "build_tag": null, "user": null, - "installer": "fuel", + "installer": "testinstaller", "scenario": "test-scenario", "trust_indicator": null, "public": "true", - "version": "euphrates", + "version": "testversion", "details": "", "criteria": "PASS", "_id": "5a45170bbb2092000e2643f6", @@ -305,7 +360,25 @@ describe('testing the result page for user', function () { ] } } - } + }, + { + request: { + path: '/api/v1/pods', + method: 'GET' + }, + response: { + data: { + pods: [ + {role: "community-ci", name: "test2", creator: "testUser", + details: "DemoDetails", mode: "metal", _id: "59f02f099a07c84bfc5c7ae5", + creation_date: "2017-10-25 11:58:25.926168"}, + {role: "production-ci", name: "test", creator: "testUser", + details: "DemoDetails", mode: "virtual", _id: "59f02f099a07c84bfc5c7aed", + creation_date: "2017-10-25 11:58:25.926168"} + ] + } + } + } ]); }); @@ -336,15 +409,15 @@ describe('testing the result page for user', function () { browser.get(baseURL+"#/results"); var filter = element(by.model('ctrl.filter')); var filterText = element(by.model('ctrl.filterText')); - filter.sendKeys('project'); - filterText.sendKeys('testproject'); + filter.sendKeys('installer'); + filterText.sendKeys('testinstaller'); var buttonFilter = element(by.buttonText('Filter')); buttonFilter.click(); var row = element.all(by.repeater('(index, result) in ctrl.data.results')).first(); var cells = row.all(by.tagName('td')); expect(cells.get(0).getText()).toContain("0e2643f5"); - filter.sendKeys('case'); - filterText.sendKeys('testcase') + filter.sendKeys('version'); + filterText.sendKeys('testversion') buttonFilter.click(); expect(cells.get(0).getText()).toContain("0e2643f6"); }); @@ -353,8 +426,8 @@ describe('testing the result page for user', function () { browser.get(baseURL+"#/results"); var filter = element(by.model('ctrl.filter')); var filterText = element(by.model('ctrl.filterText')); - filter.sendKeys('project'); - filterText.sendKeys('testproject'); + filter.sendKeys('installer'); + filterText.sendKeys('testinstaller'); var buttonFilter = element(by.buttonText('Filter')); buttonFilter.click(); var row = element.all(by.repeater('(index, result) in ctrl.data.results')).first(); @@ -370,8 +443,8 @@ describe('testing the result page for user', function () { browser.get(baseURL+"#/results"); var filter = element(by.model('ctrl.filter')); var filterText = element(by.model('ctrl.filterText')); - filter.sendKeys('project'); - filterText.sendKeys('testproject1'); + filter.sendKeys('installer'); + filterText.sendKeys('testisntaller1'); var buttonFilter = element(by.buttonText('Filter')); buttonFilter.click(); expect(element(by.css('.alert.alert-danger.ng-binding.ng-scope')) diff --git a/testapi/opnfv_testapi/tests/UI/e2e/scenariosControllerSpec.js b/testapi/opnfv_testapi/tests/UI/e2e/scenariosControllerSpec.js index bed80dd..e7c5fb0 100644 --- a/testapi/opnfv_testapi/tests/UI/e2e/scenariosControllerSpec.js +++ b/testapi/opnfv_testapi/tests/UI/e2e/scenariosControllerSpec.js @@ -32,154 +32,6 @@ describe('testing the scenarios page for anonymous user', function () { { "date": "2016-12-11 01:45", "score": "14/24" - }, - { - "date": "2016-12-15 05:28", - "score": "17/24" - }, - { - "date": "2016-12-17 03:41", - "score": "16/24" - }, - { - "date": "2018-01-22T18:30:00.000Z", - "score": "10/13" - } - ], - "trust_indicators": [ - { - "date": "2016-12-09 11:38", - "status": "silver" - }, - { - "date": "2016-12-25 08:22", - "status": "gold" - }, - { - "date": "2018-01-22T18:30:00.000Z", - "status": "sf" - }, - { - "date": "2018-01-17T18:30:00.000Z", - "status": "df" - } - ] - }, - { - "project": "functest", - "customs": [ - "vping_ssh", - "vping_userdata", - ], - "scores": [ - { - "date": "2016-12-09 11:28", - "score": "6/8" - }, - { - "date": "2016-12-14 15:34", - "score": "8/8" - }, - { - "date": "2016-12-19 13:22", - "score": "8/8" - }, - { - "date": "2016-12-22 18:17", - "score": "8/8" - }, - { - "date": "2016-12-25 08:22", - "score": "8/8" - } - ], - "trust_indicators": [ - { - "date": "2016-12-09 11:38", - "status": "silver" - } - ] - }, - { - "project": "sla", - "customs": [], - "scores": [ - { - "date": "2018-01-16T18:30:00.000Z", - "score": "sdS" - } - ], - "trust_indicators": [] - }, - { - "project": "dvsd", - "customs": [], - "scores": [], - "trust_indicators": [] - } - ] - }, - { - "owner": "dfgvds", - "version": "df", - "projects": [] - } - ] - }, - { - "installer": "fuel2", - "versions": [ - { - "owner": "testUser", - "version": "colorado", - "projects": [ - { - "project": "yardstick", - "customs": [ - "tc002", - "tc005", - "tc010", - "tc011" - ], - "scores": [ - { - "date": "2016-12-11 01:45", - "score": "14/24" - }, - { - "date": "2016-12-15 05:28", - "score": "17/24" - }, - { - "date": "2016-12-17 03:41", - "score": "16/24" - } - ], - "trust_indicators": [ - { - "date": "2016-12-09 11:38", - "status": "silver" - }, - { - "date": "2016-12-25 08:22", - "status": "gold" - } - ] - }, - { - "project": "functest", - "customs": [ - "vping_ssh", - "vping_userdata" - ], - "scores": [ - { - "date": "2016-12-09 11:28", - "score": "6/8" - }, - { - "date": "2016-12-14 15:34", - "score": "8/8" } ], "trust_indicators": [ @@ -197,7 +49,43 @@ describe('testing the scenarios page for anonymous user', function () { "_id": "5a50fcacsdgdsgdasgfvb861c", "name": "test-scenario", "creation_date": "2018-01-06 22:13:24.160407" - } + }, + { + "installers": [ + { + "installer": "fuel", + "versions": [ + { + "owner": "testUser", + "version": "colorado", + "projects": [ + { + "project": "yardstick", + "customs": [ + "dvs" + ], + "scores": [ + { + "date": "2016-12-11 01:45", + "score": "14/24" + } + ], + "trust_indicators": [ + { + "date": "2016-12-09 11:38", + "status": "silver" + } + ] + } + ] + } + ] + } + ], + "_id": "5a50fcacsdgdsgdasgfvb861d", + "name": "z-test-scenario", + "creation_date": "2018-01-06 22:13:24.160407" + } ] } } @@ -229,6 +117,15 @@ describe('testing the scenarios page for anonymous user', function () { expect(cells.get(1).getText()).toContain("test-scenario"); }); + it('Sort scenarios', function () { + browser.get(baseURL+"#/scenarios"); + var sort = element(by.xpath('//*[@id="ng-app"]/body/div/div[4]/div/table/thead/tr/th[2]/a[2]/span')) + sort.click(); + var row = element.all(by.repeater('(index, scenario) in ctrl.data.scenarios')).first(); + var cells = row.all(by.tagName('td')); + expect(cells.get(1).getText()).toContain("z-test-scenario"); + }); + it('create button is not visible for anonymous user ', function () { browser.get(baseURL+'#/scenarios'); var buttonCreate = element(by.buttonText('Create')); @@ -271,154 +168,6 @@ describe('testing the scenarios page for user', function () { { "date": "2016-12-11 01:45", "score": "14/24" - }, - { - "date": "2016-12-15 05:28", - "score": "17/24" - }, - { - "date": "2016-12-17 03:41", - "score": "16/24" - }, - { - "date": "2018-01-22T18:30:00.000Z", - "score": "10/13" - } - ], - "trust_indicators": [ - { - "date": "2016-12-09 11:38", - "status": "silver" - }, - { - "date": "2016-12-25 08:22", - "status": "gold" - }, - { - "date": "2018-01-22T18:30:00.000Z", - "status": "sf" - }, - { - "date": "2018-01-17T18:30:00.000Z", - "status": "df" - } - ] - }, - { - "project": "functest", - "customs": [ - "vping_ssh", - "vping_userdata", - ], - "scores": [ - { - "date": "2016-12-09 11:28", - "score": "6/8" - }, - { - "date": "2016-12-14 15:34", - "score": "8/8" - }, - { - "date": "2016-12-19 13:22", - "score": "8/8" - }, - { - "date": "2016-12-22 18:17", - "score": "8/8" - }, - { - "date": "2016-12-25 08:22", - "score": "8/8" - } - ], - "trust_indicators": [ - { - "date": "2016-12-09 11:38", - "status": "silver" - } - ] - }, - { - "project": "sla", - "customs": [], - "scores": [ - { - "date": "2018-01-16T18:30:00.000Z", - "score": "sdS" - } - ], - "trust_indicators": [] - }, - { - "project": "dvsd", - "customs": [], - "scores": [], - "trust_indicators": [] - } - ] - }, - { - "owner": "dfgvds", - "version": "df", - "projects": [] - } - ] - }, - { - "installer": "fuel2", - "versions": [ - { - "owner": "testUser", - "version": "colorado", - "projects": [ - { - "project": "yardstick", - "customs": [ - "tc002", - "tc005", - "tc010", - "tc011" - ], - "scores": [ - { - "date": "2016-12-11 01:45", - "score": "14/24" - }, - { - "date": "2016-12-15 05:28", - "score": "17/24" - }, - { - "date": "2016-12-17 03:41", - "score": "16/24" - } - ], - "trust_indicators": [ - { - "date": "2016-12-09 11:38", - "status": "silver" - }, - { - "date": "2016-12-25 08:22", - "status": "gold" - } - ] - }, - { - "project": "functest", - "customs": [ - "vping_ssh", - "vping_userdata" - ], - "scores": [ - { - "date": "2016-12-09 11:28", - "score": "6/8" - }, - { - "date": "2016-12-14 15:34", - "score": "8/8" } ], "trust_indicators": [ @@ -514,13 +263,13 @@ describe('testing the scenarios page for user', function () { expect(cells.get(1).getText()).toContain("test-scenario"); }); - it('create button is not visible for user ', function () { + it('create button is visible for user ', function () { browser.get(baseURL+'#/scenarios'); var buttonCreate = element(by.buttonText('Create')); expect(buttonCreate.isDisplayed()).toBe(true); }); - it('delete button is not visible for user ', function () { + it('delete button is visible for user ', function () { browser.get(baseURL+'#/scenarios'); var buttonDelete = element(by.buttonText('Delete')); expect(buttonDelete.isDisplayed()).toBe(true); diff --git a/testapi/opnfv_testapi/tests/unit/handlers/test_result.py b/testapi/opnfv_testapi/tests/unit/handlers/test_result.py index 892256a..6435367 100644 --- a/testapi/opnfv_testapi/tests/unit/handlers/test_result.py +++ b/testapi/opnfv_testapi/tests/unit/handlers/test_result.py @@ -105,18 +105,6 @@ class TestResultCreate(TestResultBase): req.details = {'1.name': 'dot_name'} return req - @executor.create(httplib.OK, '_assert_no_ti') - def test_no_ti(self): - req = copy.deepcopy(self.req_d) - req.trust_indicator = rm.TI(0) - self.actual_req = req - return req - - def _assert_no_ti(self, body): - _id = body.href.split('/')[-1] - code, body = self.get(_id) - self.assert_res(body, self.actual_req) - class TestResultGet(TestResultBase): def setUp(self): @@ -158,10 +146,6 @@ class TestResultGet(TestResultBase): return self._set_query('scenario') @executor.query(httplib.OK, '_query_success', 3) - def test_queryTrustIndicator(self): - return self._set_query('trust_indicator') - - @executor.query(httplib.OK, '_query_success', 3) def test_queryCriteria(self): return self._set_query('criteria') @@ -190,7 +174,6 @@ class TestResultGet(TestResultBase): 'installer', 'build_tag', 'scenario', - 'trust_indicator', 'criteria', period=5) @@ -202,7 +185,6 @@ class TestResultGet(TestResultBase): 'installer', 'build_tag', 'scenario', - 'trust_indicator', 'criteria', pod='notExistPod', period=1) @@ -244,8 +226,6 @@ class TestResultGet(TestResultBase): def get_value(arg): if arg in ['pod', 'project', 'case']: return getattr(self.req_d, arg + '_name') - elif arg == 'trust_indicator': - return self.req_d.trust_indicator.current else: return getattr(self.req_d, arg) @@ -255,24 +235,3 @@ class TestResultGet(TestResultBase): for k, v in kwargs.iteritems(): query.append((k, v)) return urllib.urlencode(query) - - -class TestResultUpdate(TestResultBase): - def setUp(self): - super(TestResultUpdate, self).setUp() - self.req_d_id = self._create_d() - - @executor.update(httplib.OK, '_assert_update_ti') - def test_success(self): - update_date = str(datetime.now() + timedelta(days=1)) - update_step = -0.05 - self.after_update = copy.deepcopy(self.req_d) - self.after_update.trust_indicator.current += update_step - self.after_update.trust_indicator.histories.append( - rm.TIHistory(update_date, update_step)) - update = rm.ResultUpdateRequest( - trust_indicator=self.after_update.trust_indicator) - return update, self.req_d_id - - def _assert_update_ti(self, request, body): - self.assert_res(body, self.after_update) diff --git a/testapi/opnfv_testapi/tests/unit/templates/test_result.json b/testapi/opnfv_testapi/tests/unit/templates/test_result.json index b7cb910..8f1d5fa 100644 --- a/testapi/opnfv_testapi/tests/unit/templates/test_result.json +++ b/testapi/opnfv_testapi/tests/unit/templates/test_result.json @@ -1,10 +1,6 @@ { "project_name": "functest", "scenario": "odl-l2", - "trust_indicator": { - "current": 0.7, - "histories": [] - }, "case_name": "vPing", "build_tag": "v3.0", "public": "true", diff --git a/testapi/opnfv_testapi/ui/app.js b/testapi/opnfv_testapi/ui/app.js index ada7577..b4e8d08 100644 --- a/testapi/opnfv_testapi/ui/app.js +++ b/testapi/opnfv_testapi/ui/app.js @@ -19,7 +19,7 @@ angular .module('testapiApp', [ 'ui.router','ui.bootstrap', 'cgBusy', - 'ngResource', 'angular-confirm' + 'ngResource', 'angular-confirm', 'angular-json-tree' ]); angular diff --git a/testapi/opnfv_testapi/ui/components/projects/project/testCases/testCases.html b/testapi/opnfv_testapi/ui/components/projects/project/testCases/testCases.html index ee87e0a..395db03 100644 --- a/testapi/opnfv_testapi/ui/components/projects/project/testCases/testCases.html +++ b/testapi/opnfv_testapi/ui/components/projects/project/testCases/testCases.html @@ -1,68 +1,68 @@ <div ng-controller="TestCasesController as testCasesCtrl" class="col-md-12"> -<div class="row podsTable" style="vertical-align:middle"> - <div class="col-sm-1 pull-right" ng-class="{ 'hidden': ! ((auth.projectNames.length>0) && - auth.isAuthenticated) }" > - <button type="button" class="btn btn-danger" ng-click="testCasesCtrl.openBatchDeleteModal()"> - <i class="fa fa-minus"></i> Delete</button> - </div> - <div class="col-sm-1 pull-right" ng-class="{ 'hidden': ! ((auth.projectNames.length>0) && - auth.isAuthenticated) }"> - <button type="button" class="btn btn-success" ng-click="testCasesCtrl.openCreateModal()"> - <i class="fa fa-plus"></i> Create</button> - </div> -</div> -<div class='clo-md-12'> - <div ng-show="testCasesCtrl.showError" class="alert alert-danger" role="alert"> - <span class="pull-right"> {{testCasesCtrl.error}}</span> - <span class="glyphicon glyphicon-exclamation-sign pull-right" aria-hidden="true" >Error:</span> - </div> - <div ng-show="testCasesCtrl.showSuccess" class="alert alert-success" role="alert"> - <span class="pull-right"> {{testCasesCtrl.successMessage}}</span> - <span class="glyphicon glyphicon-ok pull-right" aria-hidden="true"></span> - </div> -</div> -<div class='clo-md-12' style="padding-right:0px"> - <div class="table-responsive"> - <table class="table table-bordered table-hover" ng-data="testCasesCtrl.data.testcases"> - <thead> - <tr style=" - text-align: center;"> - <th style="width: 1%;">Bulk Select</th> - <th style="width: 19%;">Name</th> - <th style="width: 20%;">Tier</th> - <th style="width: 20%;">Blocking</th> - <th style="width: 20%;">CI Loop</th> - <th style="width: 20%;" ng-class="{'hidden': ! ((auth.projectNames.length>0) && auth.isAuthenticated)}">Operations</th> - </tr> - </thead> - <tbody> - <tr ng-repeat-start="(index, testcase) in testCasesCtrl.data.testcases" style="padding:9px"> - <td> - <div class="text-center"> - <input type="checkbox" value="{{project.name}}" ng-model="testCasesCtrl.checkBox[index]" > - </div> - </td> - <td> - <a class="text-info" ng-click="testCasesCtrl.viewTestCase(testcase.name, testcase.project_name)"> - {{testcase.name}} - </a> - </td> - <td>{{testcase.tier}}</td> - <td>{{testcase.blocking}}</td> - <td>{{testcase.ci_loop}}</td> - <td ng-class="{'hidden': ! ((auth.projectNames.length>0) && auth.isAuthenticated)}"> - <span class="podsTable-col"> - <a class="text-warning" ng-click="testCasesCtrl.openUpdateTestModal(testcase.name)" title="Edit"> - <i class="fa fa-pencil-square-o"></i></a> - <a class="text-danger" ng-click="testCasesCtrl.openDeleteTestModal(testcase.name)" title="Delete"> - <i class="fa fa-trash-o"></i></a> - </span> - </td> - </tr> - <tr ng-repeat-end=> - </tr> - </tbody> - </table> - </div> -</div> -</div> + <div class="row podsTable" style="vertical-align:middle"> + <div class="col-sm-1 pull-right" ng-class="{ 'hidden': !((auth.projectNames.length>0) && + auth.isAuthenticated) && authenticate }" > + <button type="button" class="btn btn-danger" ng-click="testCasesCtrl.openBatchDeleteModal()"> + <i class="fa fa-minus"></i> Delete</button> + </div> + <div class="col-sm-1 pull-right" ng-class="{ 'hidden': ! ((auth.projectNames.length>0) && + auth.isAuthenticated) && authenticate }"> + <button type="button" class="btn btn-success" ng-click="testCasesCtrl.openCreateModal()"> + <i class="fa fa-plus"></i> Create</button> + </div> + </div> + <div class='clo-md-12'> + <div ng-show="testCasesCtrl.showError" class="alert alert-danger" role="alert"> + <span class="pull-right"> {{testCasesCtrl.error}}</span> + <span class="glyphicon glyphicon-exclamation-sign pull-right" aria-hidden="true" >Error:</span> + </div> + <div ng-show="testCasesCtrl.showSuccess" class="alert alert-success" role="alert"> + <span class="pull-right"> {{testCasesCtrl.successMessage}}</span> + <span class="glyphicon glyphicon-ok pull-right" aria-hidden="true"></span> + </div> + </div> + <div class='clo-md-12' style="padding-right:0px"> + <div class="table-responsive"> + <table class="table table-bordered table-hover" ng-data="testCasesCtrl.data.testcases"> + <thead> + <tr style=" + text-align: center;"> + <th style="width: 1%;">Bulk Select</th> + <th style="width: 19%;">Name</th> + <th style="width: 20%;">Tier</th> + <th style="width: 20%;">Blocking</th> + <th style="width: 20%;">CI Loop</th> + <th style="width: 20%;" ng-class="{'hidden': ! ((auth.projectNames.length>0) && auth.isAuthenticated) && authenticate}">Operations</th> + </tr> + </thead> + <tbody> + <tr ng-repeat-start="(index, testcase) in testCasesCtrl.data.testcases" style="padding:9px"> + <td> + <div class="text-center"> + <input type="checkbox" value="{{project.name}}" ng-model="testCasesCtrl.checkBox[index]" > + </div> + </td> + <td> + <a class="text-info" ng-click="testCasesCtrl.viewTestCase(testcase.name, testcase.project_name)"> + {{testcase.name}} + </a> + </td> + <td>{{testcase.tier}}</td> + <td>{{testcase.blocking}}</td> + <td>{{testcase.ci_loop}}</td> + <td ng-class="{'hidden': ! ((auth.projectNames.length>0) && auth.isAuthenticated) && authenticate}"> + <span class="podsTable-col"> + <a class="text-warning" ng-click="testCasesCtrl.openUpdateTestModal(testcase.name)" title="Edit"> + <i class="fa fa-pencil-square-o"></i></a> + <a class="text-danger" ng-click="testCasesCtrl.openDeleteTestModal(testcase.name)" title="Delete"> + <i class="fa fa-trash-o"></i></a> + </span> + </td> + </tr> + <tr ng-repeat-end=> + </tr> + </tbody> + </table> + </div> + </div> + </div>
\ No newline at end of file diff --git a/testapi/opnfv_testapi/ui/components/projects/project/testCases/testCasesController.js b/testapi/opnfv_testapi/ui/components/projects/project/testCases/testCasesController.js index 9a865d3..4d6153e 100644 --- a/testapi/opnfv_testapi/ui/components/projects/project/testCases/testCasesController.js +++ b/testapi/opnfv_testapi/ui/components/projects/project/testCases/testCasesController.js @@ -21,7 +21,7 @@ TestCasesController.$inject = [ '$scope', '$http', '$filter', '$state', '$window', '$uibModal', 'testapiApiUrl','raiseAlert', - 'confirmModal' + 'confirmModal', 'authenticate' ]; /** @@ -31,7 +31,7 @@ * in them. */ function TestCasesController($scope, $http, $filter, $state, $window, $uibModal, testapiApiUrl, - raiseAlert, confirmModal) { + raiseAlert, confirmModal, authenticate) { var ctrl = this; ctrl.loadDetails = loadDetails; ctrl.name = $state.params['name']; diff --git a/testapi/opnfv_testapi/ui/components/results/result/result.html b/testapi/opnfv_testapi/ui/components/results/result/result.html index b435dce..e6b30a9 100644 --- a/testapi/opnfv_testapi/ui/components/results/result/result.html +++ b/testapi/opnfv_testapi/ui/components/results/result/result.html @@ -48,55 +48,9 @@ <td width="90%" class="podsTableLeftTd">{{ctrl.data.stop_date}}</td> </tr> <tr style="padding:9px"> - <td class="podsTableTd">Trust Indicator :</td> - <td width="90%" class="podsTableLeftTd"> - <a ng-click="ctrl.showTrustIndicator()"> - <p ng-if="ctrl.trust_indicator">Hide</p> - <p ng-if="!ctrl.trust_indicator">Show</p> - </a> - <table class="table" ng-class="{'hidden' : !ctrl.trust_indicator}" style="margin:10px"> - <tbody> - <tr style="padding:9px"></tr> - <tr style="padding:9px" > - <td class="podsTableTd">Current :</td> - <td width="90%" class="podsTableLeftTd">{{ctrl.data.trust_indicator.current}}</td> - </tr> - <tr style="padding:9px" > - <td class="podsTableTd">Histories :</td> - <td width="90%" class="podsTableLeftTd">{{ctrl.data.trust_indicator.histories}}</td> - </tr> - </tbody> - </table> - </td> - </tr> - <tr style="padding:9px"> <td class="podsTableTd">Details :</td> <td width="90%" class="podsTableLeftTd"> - <a ng-click="ctrl.showDetails()"> - <p ng-if="ctrl.details">Hide</p> - <p ng-if="!ctrl.details">Show</p> - </a> - <table class="table" ng-class="{'hidden' : !ctrl.details}" style="margin:10px"> - <tbody> - <tr style="padding:9px"></tr> - <tr style="padding:9px"> - <td class="podsTableTd">Failures :</td> - <td width="90%" class="podsTableLeftTd">{{ctrl.data.details.failures}}</td> - </tr> - <tr style="padding:9px"> - <td class="podsTableTd">Details :</td> - <td width="90%" class="podsTableLeftTd">{{ctrl.data.details.errors}}</td> - </tr> - <tr style="padding:9px"> - <td class="podsTableTd">Stream :</td> - <td width="90%" class="podsTableLeftTd"><p>{{ctrl.data.details.stream}}</p></td> - </tr> - <tr style="padding:9px"> - <td class="podsTableTd">TestsRun :</td> - <td width="90%" class="podsTableLeftTd"><p>{{ctrl.data.details.testsRun}}</p></td> - </tr> - </tbody> - </table> + <json-tree object="ctrl.json.object" root-name="object" start-expanded="true"></json-tree> </td> </tr> </tbody> diff --git a/testapi/opnfv_testapi/ui/components/results/result/resultController.js b/testapi/opnfv_testapi/ui/components/results/result/resultController.js index 028e5d8..d297b43 100644 --- a/testapi/opnfv_testapi/ui/components/results/result/resultController.js +++ b/testapi/opnfv_testapi/ui/components/results/result/resultController.js @@ -35,8 +35,10 @@ ctrl.url = testapiApiUrl + '/results'; ctrl._id = $state.params['_id']; ctrl.loadDetails = loadDetails - ctrl.showTrustIndicator = showTrustIndicator - ctrl.showDetails = showDetails + + ctrl.json = {}; + ctrl.json.string = '{"id": ""}'; + ctrl.json.object = JSON.parse(ctrl.json.string); /** *Contact the testapi and retrevie the result details @@ -47,6 +49,8 @@ ctrl.podsRequest = $http.get(resultUrl).success(function (data) { ctrl.data = data; + ctrl.object=JSON.stringify(ctrl.data.details) + ctrl.json.object = JSON.parse(ctrl.object) }).catch(function (error) { ctrl.data = null; ctrl.showError = true; @@ -54,21 +58,6 @@ }); } - function showTrustIndicator(){ - if(ctrl.trust_indicator){ - ctrl.trust_indicator = false - }else{ - ctrl.trust_indicator = true - } - } - - function showDetails(){ - if(ctrl.details){ - ctrl.details = false - }else{ - ctrl.details = true - } - } ctrl.loadDetails(); } })();
\ No newline at end of file diff --git a/testapi/opnfv_testapi/ui/components/scenarios/scenarios.html b/testapi/opnfv_testapi/ui/components/scenarios/scenarios.html index 9057b0f..bde946c 100644 --- a/testapi/opnfv_testapi/ui/components/scenarios/scenarios.html +++ b/testapi/opnfv_testapi/ui/components/scenarios/scenarios.html @@ -27,7 +27,14 @@ <tr style=" text-align: center;"> <th style="width: 1%;">Bulk Select</th> - <th style="width: 80%;">Name</th> + <th style="width: 80%;">Name + <a class="text-danger" ng-click="ctrl.sortBy()" ng-class="{ 'hidden': ctrl.sortName }" > + <span class="glyphicon glyphicon-sort-by-alphabet pull-right" aria-hidden="true"></span> + </a> + <a class="text-danger" ng-click="ctrl.sortBy()" ng-class="{ 'hidden': !ctrl.sortName}" > + <span class="glyphicon glyphicon-sort-by-alphabet-alt pull-right" aria-hidden="true"></span> + </a> + </th> <th style="width: 19%;" ng-class="{'hidden': !auth.isAuthenticated}">Operations</th> </tr> </thead> diff --git a/testapi/opnfv_testapi/ui/components/scenarios/scenariosController.js b/testapi/opnfv_testapi/ui/components/scenarios/scenariosController.js index 98e4089..240287c 100644 --- a/testapi/opnfv_testapi/ui/components/scenarios/scenariosController.js +++ b/testapi/opnfv_testapi/ui/components/scenarios/scenariosController.js @@ -21,7 +21,7 @@ ScenariosController.$inject = [ '$scope', '$http', '$filter', '$state', '$window', '$uibModal', 'testapiApiUrl', - 'raiseAlert', 'confirmModal' + 'raiseAlert', 'confirmModal', 'sortService' ]; /** @@ -30,7 +30,7 @@ * through projects declared in TestAPI. */ function ScenariosController($scope, $http, $filter, $state, $window, $uibModal, testapiApiUrl, - raiseAlert, confirmModal) { + raiseAlert, confirmModal, sortService) { var ctrl = this; ctrl.url = testapiApiUrl + '/scenarios'; @@ -44,8 +44,9 @@ ctrl.deleteScenario = deleteScenario; ctrl.openBatchDeleteModal = openBatchDeleteModal; ctrl.deleteBatchScenario = deleteBatchScenario - + ctrl.sortBy = sortBy ctrl.checkBox = []; + ctrl.sortName = false function openUpdateModal(name){ $uibModal.open({ @@ -68,6 +69,11 @@ confirmModal("Delete", 'scenarios', ctrl.deleteScenario,name); } + function sortBy(){ + ctrl.data.scenarios = sortService.sortFunction(ctrl.data.scenarios, 'name' , ctrl.sortName) + ctrl.sortName=!ctrl.sortName + } + function deleteScenario(name){ var scenarioURL = ctrl.url+"/"+name; ctrl.scenarioRequest = @@ -142,6 +148,7 @@ ctrl.resultsRequest = $http.get(ctrl.url).success(function (data) { ctrl.data = data; + ctrl.sortBy() }).catch(function (data) { ctrl.data = null; ctrl.showError = true; diff --git a/testapi/opnfv_testapi/ui/index.html b/testapi/opnfv_testapi/ui/index.html index 68c6cc5..f345197 100644 --- a/testapi/opnfv_testapi/ui/index.html +++ b/testapi/opnfv_testapi/ui/index.html @@ -28,6 +28,7 @@ <link rel="stylesheet" href="testapi-ui/assets/lib/angular-busy/dist/angular-busy.min.css"> <link rel="stylesheet" href="testapi-ui/assets/css/style.css"> <link rel="stylesheet" href="testapi-ui/assets/lib/font-awesome-4.7.0/css/font-awesome.min.css"> + <link rel="stylesheet" href="testapi-ui/assets/lib/angular-json-tree/angular-json-tree.css" /> <script src="testapi-ui/assets/lib/jquery/jquery-3.2.1.min.js"></script> <script src="testapi-ui/assets/lib/bootstrap/dist/js/bootstrap.min.js"></script> @@ -36,6 +37,7 @@ <script src="testapi-ui/assets/lib/angular-resource/angular-resource.min.js"></script> <script src="testapi-ui/assets/lib/angular-bootstrap/ui-bootstrap-tpls.min.js"></script> <script src="testapi-ui/assets/lib/angular-busy/dist/angular-busy.min.js"></script> + <script src="testapi-ui/assets/lib/angular-json-tree/angular-json-tree.min.js"></script> <script src="testapi-ui/assets/lib/angular-confirm-modal/angular-confirm.js"></script> <script src="testapi-ui/app.js"></script> diff --git a/testapi/testapi-client/setup.cfg b/testapi/testapi-client/setup.cfg index 72a5a57..f085f59 100644 --- a/testapi/testapi-client/setup.cfg +++ b/testapi/testapi-client/setup.cfg @@ -26,6 +26,17 @@ testapi = project delete = testapiclient.cli.projects:ProjectDelete project put = testapiclient.cli.projects:ProjectPut + testcase create = testapiclient.cli.testcases:TestcaseCreate + testcase get = testapiclient.cli.testcases:TestcaseGet + testcase getone = testapiclient.cli.testcases:TestcaseGetOne + testcase delete = testapiclient.cli.testcases:TestcaseDelete + testcase put = testapiclient.cli.testcases:TestcasePut + + scenario create = testapiclient.cli.scenarios:ScenarioCreate + scenario get = testapiclient.cli.scenarios:ScenarioGet + scenario getone = testapiclient.cli.scenarios:ScenarioGetOne + scenario delete = testapiclient.cli.scenarios:ScenarioDelete + scenario put = testapiclient.cli.scenarios:ScenarioPut [egg_info] tag_build = tag_date = 0 diff --git a/testapi/testapi-client/testapiclient/cli/scenarios.py b/testapi/testapi-client/testapiclient/cli/scenarios.py new file mode 100644 index 0000000..fc6a2db --- /dev/null +++ b/testapi/testapi-client/testapiclient/cli/scenarios.py @@ -0,0 +1,131 @@ +import json + +from testapiclient.utils import command +from testapiclient.utils import urlparse + + +def scenarios_url(): + return urlparse.resource_join('scenarios') + + +def scenario_url(parsed_args): + return urlparse.path_join(scenarios_url(), parsed_args.name) + + +class ScenarioGet(command.Lister): + + def get_parser(self, prog_name): + parser = super(ScenarioGet, self).get_parser(prog_name) + parser.add_argument('-name', + help='Search scenarios using name') + parser.add_argument('-installer', + help='Search scenarios using installer') + parser.add_argument('---version', + help='Search scenarios using version') + parser.add_argument('-project', + help='Search scenarios using project') + return parser + + def take_action(self, parsed_args): + columns = ( + 'name', + '_id', + 'creator', + 'creation_date' + ) + data = self.app.client_manager.get( + urlparse.query_by(scenarios_url(), + ['name', 'installer', 'version', 'project'], + parsed_args)) + return self.format_output(columns, data.get('scenarios', [])) + + +class ScenarioGetOne(command.ShowOne): + + def get_parser(self, prog_name): + parser = super(ScenarioGetOne, self).get_parser(prog_name) + parser.add_argument('name', + help='Search scenario by name') + return parser + + def take_action(self, parsed_args): + return self.format_output( + self.app.client_manager.get(scenario_url(parsed_args))) + + +class ScenarioCreate(command.ShowOne): + + def get_parser(self, prog_name): + parser = super(ScenarioCreate, self).get_parser(prog_name) + parser.add_argument('scenario', + type=json.loads, + help='Scenario create request format :\n' + '\'{ "installers": [], "name": ""}\',\n' + 'Intaller create request format :\n' + '\'{"installer": "","versions": []}\',\n' + 'Version create request format :\n' + '\'{"owner": "","version": "",' + '"projects": []}\',\n' + 'Project create request format :\n' + '\'{"project": "","customs": [],' + '"scores": [],' + '"trust_indicators": []}\',\n' + 'Custom create request format :\n' + '\'["asf","saf"]\',\n' + 'Score create request format :\n' + '\'{"date": "", "score": ""}\',\n' + 'Trust Indicators create request format :\n' + '\'{"date": "", "status": ""}\'') + return parser + + def take_action(self, parsed_args): + return self.format_output( + self.app.client_manager.post( + scenarios_url(), parsed_args.scenario)) + + +class ScenarioDelete(command.Command): + + def get_parser(self, prog_name): + parser = super(ScenarioDelete, self).get_parser(prog_name) + parser.add_argument('name', + type=str, + help='Delete scenario by name') + return parser + + def take_action(self, parsed_args): + return self.app.client_manager.delete(scenario_url(parsed_args)) + + +class ScenarioPut(command.ShowOne): + + def get_parser(self, prog_name): + parser = super(ScenarioPut, self).get_parser(prog_name) + parser.add_argument('name', + type=str, + help='Update scenario by name') + parser.add_argument('scenario', + type=json.loads, + help='Scenario create request format :\n' + '\'{ "installers": [], "name": ""}\',\n' + 'Intaller create request format :\n' + '\'{"installer": "","versions": []}\',\n' + 'Version create request format :\n' + '\'{"owner": "","version": "",' + '"projects": []}\',\n' + 'Project create request format :\n' + '\'{"project": "","customs": [],' + '"scores": [],' + '"trust_indicators": []}\',\n' + 'Custom create request format :\n' + '\'["asf","saf"]\',\n' + 'Score create request format :\n' + '\'{"date": "", "score": ""}\',\n' + 'Trust Indicators create request format :\n' + '\'{"date": "", "status": ""}\'') + return parser + + def take_action(self, parsed_args): + return self.format_output( + self.app.client_manager.put( + scenario_url(parsed_args), parsed_args.scenario)) diff --git a/testapi/testapi-client/testapiclient/cli/testcases.py b/testapi/testapi-client/testapiclient/cli/testcases.py new file mode 100644 index 0000000..6c97edb --- /dev/null +++ b/testapi/testapi-client/testapiclient/cli/testcases.py @@ -0,0 +1,119 @@ +import json + +from testapiclient.utils import command +from testapiclient.utils import urlparse + + +def testcases_url(name): + return urlparse.resource_join('projects', name, 'cases') + + +def testcase_url(parsed_args): + return urlparse.path_join( + testcases_url(parsed_args.project_name), parsed_args.name) + + +class TestcaseGet(command.Lister): + + def get_parser(self, prog_name): + parser = super(TestcaseGet, self).get_parser(prog_name) + parser.add_argument('--project-name', + required=True, + help='Search testcases by project name') + return parser + + def take_action(self, parsed_args): + columns = ( + 'name', + '_id', + 'creator', + 'creation_date' + ) + data = self.app.client_manager.get( + testcases_url(parsed_args.project_name)) + return self.format_output(columns, data.get('testcases', [])) + + +class TestcaseGetOne(command.ShowOne): + + def get_parser(self, prog_name): + parser = super(TestcaseGetOne, self).get_parser(prog_name) + parser.add_argument('--project-name', + required=True, + help='Search testcase by project name') + parser.add_argument('name', + help='Search testcase by name') + return parser + + def take_action(self, parsed_args): + return self.format_output( + self.app.client_manager.get(testcase_url(parsed_args))) + + +class TestcaseCreate(command.ShowOne): + + def get_parser(self, prog_name): + parser = super(TestcaseCreate, self).get_parser(prog_name) + parser.add_argument('--project-name', + required=True, + help='Create testcase under project name') + parser.add_argument('testcase', + type=json.loads, + help='Testcase create request format:\n' + '\'{"run": "", "name": "", "ci_loop": "",' + '"tags": "",\n "url": "", "blocking": "",' + '"domains": "", "dependencies": "",\n ' + '"version": "", "criteria": "", "tier": "",' + '"trust": "",\n "catalog_description": "",' + '"description": ""}\'') + return parser + + def take_action(self, parsed_args): + return self.format_output( + self.app.client_manager.post( + testcases_url(parsed_args.project_name), parsed_args.testcase)) + + +class TestcaseDelete(command.Command): + + def get_parser(self, prog_name): + parser = super(TestcaseDelete, self).get_parser(prog_name) + parser.add_argument('--project-name', + required=True, + type=str, + help='Delete testcase by project name') + parser.add_argument('name', + type=str, + help='Delete testcase by name') + return parser + + def take_action(self, parsed_args): + return self.app.client_manager.delete(testcase_url(parsed_args)) + + +class TestcasePut(command.ShowOne): + + def get_parser(self, prog_name): + parser = super(TestcasePut, self).get_parser(prog_name) + parser.add_argument('--project-name', + type=str, + required=True, + help='Update testcase by project name') + parser.add_argument('name', + type=str, + help='Update testcase by name') + parser.add_argument('testcase', + type=json.loads, + help='Testcase Update request format:\n' + '\'{"run": "", "name": "", "ci_loop": "",' + '"tags": "",\n "url": "", "blocking": "",' + '"domains": "", "dependencies": "",\n ' + '"version": "", "criteria": "", "tier": "",' + '"trust": "",\n "catalog_description": "",' + '"description": ""}\'') + return parser + + def take_action(self, parsed_args): + return self.format_output( + self.app.client_manager.put( + testcase_url(parsed_args), parsed_args.testcase)) diff --git a/testapi/testapi-client/testapiclient/tests/unit/test_scenario.py b/testapi/testapi-client/testapiclient/tests/unit/test_scenario.py new file mode 100644 index 0000000..2458d2b --- /dev/null +++ b/testapi/testapi-client/testapiclient/tests/unit/test_scenario.py @@ -0,0 +1,152 @@ +import json + +from mock import mock +from six.moves.urllib import parse +import testtools + +from testapiclient.cli import scenarios +from testapiclient.tests.unit import fakes as fk +from testapiclient.tests.unit import utils +from testapiclient.utils import clientmanager + + +class ScenarioTest(utils.TestCommand): + def setUp(self): + super(ScenarioTest, self).setUp() + self.base_url = parse.urljoin(self.api_url, 'scenarios') + self.scenario_json = { + "installers": [], + "name": "test_scenario" + } + self.scenario_string = json.dumps(self.scenario_json) + + +class ScenarioGetTest(ScenarioTest): + + def setUp(self): + super(ScenarioGetTest, self).setUp() + self.scenarios_rsp = {'scenarios': [self.scenario_json]} + + def test_get(self): + self.get_mock.return_value = fk.FakeResponse(data=self.scenarios_rsp) + scenario_get = scenarios.ScenarioGet(self.app, mock.Mock()) + args = ['-name', 's1', '-installer', + 'i1', '---version', 'v1', '-project', 'p1'] + verifies = [ + ('name', 's1'), + ('installer', 'i1'), + ('version', 'v1'), + ('project', 'p1')] + parsed_args = self.check_parser(scenario_get, args, verifies) + scenario_get.take_action(parsed_args) + kall = self.get_mock.call_args + args, kwargs = kall + self.assert_url( + args[0], + self.base_url + '?version=v1&name=s1&installer=i1&project=p1') + + def assert_url(self, actual_url, expected_url): + actual_parsed = parse.parse_qs(parse.urlparse(actual_url).query) + expected_parsed = parse.parse_qs(parse.urlparse(expected_url).query) + assert actual_parsed == expected_parsed + + def test_get_all(self): + self.get_mock.return_value = fk.FakeResponse(data=self.scenarios_rsp) + scenario_get = scenarios.ScenarioGet(self.app, mock.Mock()) + args = [] + verifies = [] + parsed_args = self.check_parser(scenario_get, args, verifies) + scenario_get.take_action(parsed_args) + self.get_mock.assert_called_once_with( + self.base_url, + headers=clientmanager.ClientManager.headers) + + def test_get_one(self): + self.get_mock.return_value = fk.FakeResponse(data=self.scenario_json) + scenario_get_one = scenarios.ScenarioGetOne(self.app, mock.Mock()) + args = ['def'] + verifies = [('name', 'def')] + parsed_args = self.check_parser(scenario_get_one, args, verifies) + scenario_get_one.take_action(parsed_args) + self.get_mock.assert_called_once_with( + self.base_url + '/def', + headers=clientmanager.ClientManager.headers) + + +class ScenarioCreateTest(ScenarioTest): + + def setUp(self): + super(ScenarioCreateTest, self).setUp() + + def test_create_success(self): + succ_rsp = { + 'href': '{}/{}'.format(self.base_url, + self.scenario_json.get('name')) + } + self.post_mock.return_value = fk.FakeResponse(data=succ_rsp) + scenario_create = scenarios.ScenarioCreate(self.app, mock.Mock()) + args = [self.scenario_string] + verifies = [('scenario', self.scenario_json)] + parsed_args = self.check_parser(scenario_create, args, verifies) + scenario_create.take_action(parsed_args) + self.post_mock.assert_called_once() + + def test_create_failure(self): + with testtools.ExpectedException(Exception, 'Create failed: Error'): + self.post_mock.return_value = utils.FAKE_FAILURE + scenario_create = scenarios.ScenarioCreate(self.app, mock.Mock()) + args = [self.scenario_string] + verifies = [('scenario', self.scenario_json)] + parsed_args = self.check_parser(scenario_create, args, verifies) + scenario_create.take_action(parsed_args) + + +class ScenarioDeleteTest(ScenarioTest): + + def setUp(self): + super(ScenarioDeleteTest, self).setUp() + + def test_delete_success(self): + self.delete_mock.return_value = fk.FakeResponse() + scenario_delete = scenarios.ScenarioDelete(self.app, mock.Mock()) + args = ['def'] + verifies = [('name', 'def')] + parsed_args = self.check_parser(scenario_delete, args, verifies) + scenario_delete.take_action(parsed_args) + self.delete_mock.assert_called_once_with( + self.base_url + '/def', + data=None, + headers=clientmanager.ClientManager.headers) + + def test_delete_failure(self): + with testtools.ExpectedException(Exception, 'Delete failed: Error'): + self.delete_mock.return_value = utils.FAKE_FAILURE + scenario_delete = scenarios.ScenarioDelete(self.app, mock.Mock()) + args = ['def'] + verifies = [('name', 'def')] + parsed_args = self.check_parser(scenario_delete, args, verifies) + scenario_delete.take_action(parsed_args) + + +class ScenarioPutTest(ScenarioTest): + + def setUp(self): + super(ScenarioPutTest, self).setUp() + + def test_put_success(self): + self.put_mock.return_value = fk.FakeResponse(data=self.scenario_json) + scenario_put = scenarios.ScenarioPut(self.app, mock.Mock()) + args = ['def', self.scenario_string] + verifies = [('name', 'def'), ('scenario', self.scenario_json)] + parsed_args = self.check_parser(scenario_put, args, verifies) + scenario_put.take_action(parsed_args) + self.put_mock.assert_called_once() + + def test_put_failure(self): + with testtools.ExpectedException(Exception, 'Update failed: Error'): + self.put_mock.return_value = utils.FAKE_FAILURE + scenario_put = scenarios.ScenarioPut(self.app, mock.Mock()) + args = ['def', self.scenario_string] + verifies = [('name', 'def'), ('scenario', self.scenario_json)] + parsed_args = self.check_parser(scenario_put, args, verifies) + scenario_put.take_action(parsed_args) diff --git a/testapi/testapi-client/testapiclient/tests/unit/test_testcases.py b/testapi/testapi-client/testapiclient/tests/unit/test_testcases.py new file mode 100644 index 0000000..6fd2120 --- /dev/null +++ b/testapi/testapi-client/testapiclient/tests/unit/test_testcases.py @@ -0,0 +1,155 @@ +import json + +from mock import mock +from six.moves.urllib import parse +import testtools + +from testapiclient.cli import testcases +from testapiclient.tests.unit import fakes +from testapiclient.tests.unit import utils +from testapiclient.utils import clientmanager + + +class TestcaseTest(utils.TestCommand): + def setUp(self): + super(TestcaseTest, self).setUp() + self.base_url = parse.urljoin(self.api_url, 'projects/{}/cases') + self.project_name = 'functest' + self.testcase_json = { + 'run': '', + 'name': 'test-case', + 'ci_loop': '', + 'tags': '', + 'url': '', + 'blocking': '', + 'domains': '', + 'dependencies': '', + 'version': '', + 'criteria': '', + 'tier': '', + 'trust': '', + 'catalog_description': '', + 'description': '' + } + self.testcase_string = json.dumps(self.testcase_json) + + +class TestcaseGetTest(TestcaseTest): + + def setUp(self): + super(TestcaseGetTest, self).setUp() + self.testcases_rsp = {'testcases': [self.testcase_json]} + + def test_get(self): + self.get_mock.return_value = fakes.FakeResponse( + data=self.testcases_rsp) + testcase_get = testcases.TestcaseGet(self.app, mock.Mock()) + args = ['--project-name', 'dfs'] + verifies = [('project_name', 'dfs')] + parsed_args = self.check_parser(testcase_get, args, verifies) + testcase_get.take_action(parsed_args) + self.get_mock.assert_called_once_with( + self.base_url.format(parsed_args.project_name), + headers=clientmanager.ClientManager.headers) + + def test_get_one(self): + self.get_mock.return_value = fakes.FakeResponse( + data=self.testcase_json) + testcase_get_one = testcases.TestcaseGetOne(self.app, mock.Mock()) + args = ['--project-name', 'functest', 'def'] + verifies = [('project_name', 'functest'), ('name', 'def')] + parsed_args = self.check_parser(testcase_get_one, args, verifies) + testcase_get_one.take_action(parsed_args) + self.get_mock.assert_called_once_with( + self.base_url.format(parsed_args.project_name) + '/def', + headers=clientmanager.ClientManager.headers) + + +class TestcaseCreateTest(TestcaseTest): + + def setUp(self): + super(TestcaseCreateTest, self).setUp() + + def test_create_success(self): + succ_rsp = { + 'href': '{}/{}'.format(self.base_url.format(self.project_name), + self.testcase_json.get('name')) + } + self.post_mock.return_value = fakes.FakeResponse(data=succ_rsp) + testcase_create = testcases.TestcaseCreate(self.app, mock.Mock()) + args = ['--project-name', 'functest', self.testcase_string] + verifies = [ + ('project_name', 'functest'), + ('testcase', self.testcase_json)] + parsed_args = self.check_parser(testcase_create, args, verifies) + testcase_create.take_action(parsed_args) + self.post_mock.assert_called_once() + + def test_create_failure(self): + with testtools.ExpectedException(Exception, 'Create failed: Error'): + self.post_mock.return_value = utils.FAKE_FAILURE + testcase_create = testcases.TestcaseCreate(self.app, mock.Mock()) + args = ['--project-name', 'functest', self.testcase_string] + verifies = [ + ('project_name', 'functest'), + ('testcase', self.testcase_json)] + parsed_args = self.check_parser(testcase_create, args, verifies) + testcase_create.take_action(parsed_args) + + +class TestcaseDeleteTest(TestcaseTest): + + def setUp(self): + super(TestcaseDeleteTest, self).setUp() + + def test_delete_success(self): + self.delete_mock.return_value = fakes.FakeResponse() + testcase_delete = testcases.TestcaseDelete(self.app, mock.Mock()) + args = ['--project-name', 'functest', 'def'] + verifies = [('project_name', 'functest'), ('name', 'def')] + parsed_args = self.check_parser(testcase_delete, args, verifies) + testcase_delete.take_action(parsed_args) + self.delete_mock.assert_called_once_with( + self.base_url.format(parsed_args.project_name) + '/def', + data=None, + headers=clientmanager.ClientManager.headers) + + def test_delete_failure(self): + with testtools.ExpectedException(Exception, 'Delete failed: Error'): + self.delete_mock.return_value = utils.FAKE_FAILURE + testcase_delete = testcases.TestcaseDelete(self.app, mock.Mock()) + args = ['--project-name', 'functest', 'def'] + verifies = [('project_name', 'functest'), ('name', 'def')] + parsed_args = self.check_parser(testcase_delete, args, verifies) + testcase_delete.take_action(parsed_args) + + +class TestcasePutTest(TestcaseTest): + + def setUp(self): + super(TestcasePutTest, self).setUp() + + def test_put_success(self): + self.put_mock.return_value = fakes.FakeResponse( + data=self.testcase_json) + testcase_put = testcases.TestcasePut(self.app, mock.Mock()) + args = ['--project-name', 'functest', 'def', self.testcase_string] + verifies = [ + ('project_name', 'functest'), + ('name', 'def'), + ('testcase', self.testcase_json)] + parsed_args = self.check_parser(testcase_put, args, verifies) + testcase_put.take_action(parsed_args) + self.put_mock.assert_called_once() + + def test_put_failure(self): + with testtools.ExpectedException(Exception, 'Update failed: Error'): + self.put_mock.return_value = utils.FAKE_FAILURE + testcase_put = testcases.TestcasePut(self.app, mock.Mock()) + args = ['--project-name', 'functest', 'def', self.testcase_string] + verifies = [ + ('project_name', 'functest'), + ('name', 'def'), + ('testcase', self.testcase_json)] + parsed_args = self.check_parser(testcase_put, args, verifies) + testcase_put.take_action(parsed_args) diff --git a/testapi/testapi-client/testapiclient/utils/urlparse.py b/testapi/testapi-client/testapiclient/utils/urlparse.py index 9f99a46..47d40d5 100644 --- a/testapi/testapi-client/testapiclient/utils/urlparse.py +++ b/testapi/testapi-client/testapiclient/utils/urlparse.py @@ -17,9 +17,9 @@ def query_join(base, **queries): return base + '?' + parse.urlencode(queries) -def resource_join(url): +def resource_join(*url): testapi_url = os.environ.get('testapi_url') - return path_join(testapi_url, url) + return path_join(testapi_url, *url) def get_queries(queries, parsed_args): |