summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--ci/htmlize/htmlize.py6
-rw-r--r--testapi/3rd_party/static/testapi-ui/assets/css/style.css12
-rw-r--r--testapi/3rd_party/static/testapi-ui/assets/lib/angular-json-tree/angular-json-tree.css76
-rw-r--r--testapi/3rd_party/static/testapi-ui/assets/lib/angular-json-tree/angular-json-tree.min.js67
-rw-r--r--testapi/opnfv_testapi/handlers/result_handlers.py24
-rw-r--r--testapi/opnfv_testapi/models/result_models.py67
-rw-r--r--testapi/opnfv_testapi/tests/UI/e2e/authenticateFalseSpec.js157
-rw-r--r--testapi/opnfv_testapi/tests/UI/e2e/projectsControllerSpec.js20
-rw-r--r--testapi/opnfv_testapi/tests/UI/e2e/resultsControllerSpec.js141
-rw-r--r--testapi/opnfv_testapi/tests/UI/e2e/scenariosControllerSpec.js347
-rw-r--r--testapi/opnfv_testapi/tests/unit/handlers/test_result.py41
-rw-r--r--testapi/opnfv_testapi/tests/unit/templates/test_result.json4
-rw-r--r--testapi/opnfv_testapi/ui/app.js2
-rw-r--r--testapi/opnfv_testapi/ui/components/projects/project/testCases/testCases.html134
-rw-r--r--testapi/opnfv_testapi/ui/components/projects/project/testCases/testCasesController.js4
-rw-r--r--testapi/opnfv_testapi/ui/components/results/result/result.html48
-rw-r--r--testapi/opnfv_testapi/ui/components/results/result/resultController.js23
-rw-r--r--testapi/opnfv_testapi/ui/components/scenarios/scenarios.html9
-rw-r--r--testapi/opnfv_testapi/ui/components/scenarios/scenariosController.js13
-rw-r--r--testapi/opnfv_testapi/ui/index.html2
-rw-r--r--testapi/testapi-client/setup.cfg11
-rw-r--r--testapi/testapi-client/testapiclient/cli/scenarios.py131
-rw-r--r--testapi/testapi-client/testapiclient/cli/testcases.py119
-rw-r--r--testapi/testapi-client/testapiclient/tests/unit/test_scenario.py152
-rw-r--r--testapi/testapi-client/testapiclient/tests/unit/test_testcases.py155
-rw-r--r--testapi/testapi-client/testapiclient/utils/urlparse.py4
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">&nbsp;{{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">&nbsp;{{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&nbsp;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">&nbsp;{{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">&nbsp;{{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&nbsp;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&nbsp;Indicator&nbsp;:</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&nbsp;:</td>
- <td width="90%" class="podsTableLeftTd">{{ctrl.data.trust_indicator.current}}</td>
- </tr>
- <tr style="padding:9px" >
- <td class="podsTableTd">Histories&nbsp;:</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&nbsp;:</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&nbsp;:</td>
- <td width="90%" class="podsTableLeftTd">{{ctrl.data.details.failures}}</td>
- </tr>
- <tr style="padding:9px">
- <td class="podsTableTd">Details&nbsp;:</td>
- <td width="90%" class="podsTableLeftTd">{{ctrl.data.details.errors}}</td>
- </tr>
- <tr style="padding:9px">
- <td class="podsTableTd">Stream&nbsp;:</td>
- <td width="90%" class="podsTableLeftTd"><p>{{ctrl.data.details.stream}}</p></td>
- </tr>
- <tr style="padding:9px">
- <td class="podsTableTd">TestsRun&nbsp;:</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&nbsp;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):