summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--INFO.yaml47
-rw-r--r--ci/htmlize/htmlize.py6
-rw-r--r--ci/htmlize/push-doc-artifacts.sh (renamed from ci/htmlize/push-doc-artifact.sh)0
-rw-r--r--reporting/3rd_party/html/colorado.html (renamed from reporting/html/colorado.html)2
-rw-r--r--reporting/3rd_party/html/danube.html (renamed from reporting/html/danube.html)2
-rw-r--r--reporting/3rd_party/html/elements.html (renamed from reporting/html/elements.html)0
-rw-r--r--reporting/3rd_party/html/euphrates.html (renamed from reporting/html/euphrates.html)2
-rw-r--r--reporting/3rd_party/html/fraser.html (renamed from reporting/html/functest-colorado.html)265
-rw-r--r--reporting/3rd_party/html/functest.html (renamed from reporting/html/functest-euphrates.html)29
-rw-r--r--reporting/3rd_party/html/gambia.html (renamed from reporting/html/functest-danube.html)79
-rw-r--r--reporting/3rd_party/html/generic.html (renamed from reporting/html/generic.html)0
-rw-r--r--reporting/3rd_party/html/index.html (renamed from reporting/html/index.html)33
-rw-r--r--reporting/3rd_party/html/master.html (renamed from reporting/html/master.html)2
-rw-r--r--reporting/api/conf.py4
-rw-r--r--reporting/api/extension/__init__.py0
-rw-r--r--reporting/api/extension/client.py15
-rw-r--r--reporting/api/handlers/scenarios.py27
-rw-r--r--reporting/api/server.py8
-rw-r--r--reporting/api/service/__init__.py0
-rw-r--r--reporting/api/service/result.py90
-rw-r--r--reporting/api/service/scenario.py133
-rw-r--r--reporting/api/urls.py5
-rw-r--r--reporting/css/default.css4
-rwxr-xr-xreporting/docker/reporting.sh4
-rw-r--r--reporting/html/functest-master.html124
-rw-r--r--reporting/img/fraser.jpgbin0 -> 45629 bytes
-rw-r--r--reporting/img/gambia.jpgbin0 -> 45206 bytes
-rw-r--r--reporting/js/gauge.js4
-rw-r--r--reporting/pages/app/index.html1
-rw-r--r--reporting/pages/app/scripts/config.router.js21
-rw-r--r--reporting/pages/app/scripts/controllers/gating.controller.js119
-rw-r--r--reporting/pages/app/scripts/factory/table.factory.js12
-rw-r--r--reporting/pages/app/views/gating.html68
-rw-r--r--reporting/reporting/bottlenecks/reporting-status.py6
-rwxr-xr-xreporting/reporting/functest/reporting-status.py127
-rwxr-xr-xreporting/reporting/functest/reporting-tempest.py26
-rwxr-xr-xreporting/reporting/functest/reporting-vims.py2
-rw-r--r--reporting/reporting/functest/template/index-status-tmpl.html25
-rw-r--r--reporting/reporting/functest/testCase.py76
-rw-r--r--reporting/reporting/reporting.yaml6
-rw-r--r--reporting/reporting/vsperf/reporting-status.py2
-rw-r--r--reporting/reporting/yardstick/reporting-status.py3
-rw-r--r--testapi/3rd_party/static/testapi-ui/assets/css/style.css61
-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/docker/Dockerfile43
-rwxr-xr-xtestapi/docker/prepare-env.sh24
-rw-r--r--testapi/docs/developer/devguide/images/CAS-sequence.jpgbin0 -> 11785 bytes
-rw-r--r--testapi/docs/developer/devguide/testapi-client-import.rst974
-rw-r--r--testapi/docs/developer/devguide/testapi-client.rst858
-rw-r--r--testapi/docs/developer/devguide/web-portal.rst114
-rw-r--r--testapi/docs/internship/webportal.rst169
-rw-r--r--testapi/opnfv_testapi/common/check.py24
-rw-r--r--testapi/opnfv_testapi/handlers/sign_handlers.py2
-rw-r--r--testapi/opnfv_testapi/tests/UI/e2e/authenticateFalseSpec.js233
-rw-r--r--testapi/opnfv_testapi/tests/UI/e2e/deployResultsControllerSpec.js2
-rw-r--r--testapi/opnfv_testapi/tests/UI/e2e/podsControllerSpec.js36
-rw-r--r--testapi/opnfv_testapi/tests/UI/e2e/projectsControllerSpec.js74
-rw-r--r--testapi/opnfv_testapi/tests/UI/e2e/resultsControllerSpec.js138
-rw-r--r--testapi/opnfv_testapi/tests/UI/e2e/scenarioControllerSpec.js45
-rw-r--r--testapi/opnfv_testapi/tests/UI/e2e/scenariosControllerSpec.js387
-rw-r--r--testapi/opnfv_testapi/tests/UI/e2e/testCasesControllerSpec.js25
-rw-r--r--testapi/opnfv_testapi/tests/unit/executor.py8
-rw-r--r--testapi/opnfv_testapi/tests/unit/fake_pymongo.py6
-rw-r--r--testapi/opnfv_testapi/tests/unit/handlers/test_base.py4
-rw-r--r--testapi/opnfv_testapi/tests/unit/handlers/test_testcase.py31
-rw-r--r--testapi/opnfv_testapi/ui/Gruntfile.js17
-rw-r--r--testapi/opnfv_testapi/ui/app.js17
-rw-r--r--testapi/opnfv_testapi/ui/components/deploy-results/deploy-result/deployResult.html68
-rw-r--r--testapi/opnfv_testapi/ui/components/deploy-results/deploy-result/deployResultController.js21
-rw-r--r--testapi/opnfv_testapi/ui/components/pods/pod/pod.html30
-rw-r--r--testapi/opnfv_testapi/ui/components/pods/pod/podController.js8
-rw-r--r--testapi/opnfv_testapi/ui/components/pods/pods.html16
-rw-r--r--testapi/opnfv_testapi/ui/components/pods/podsController.js45
-rw-r--r--testapi/opnfv_testapi/ui/components/projects/project/project.html22
-rw-r--r--testapi/opnfv_testapi/ui/components/projects/project/projectController.js6
-rw-r--r--testapi/opnfv_testapi/ui/components/projects/project/testCases/testCase/testCase.html70
-rw-r--r--testapi/opnfv_testapi/ui/components/projects/project/testCases/testCase/testCaseController.js6
-rw-r--r--testapi/opnfv_testapi/ui/components/projects/project/testCases/testCases.html130
-rw-r--r--testapi/opnfv_testapi/ui/components/projects/project/testCases/testCasesController.js68
-rw-r--r--testapi/opnfv_testapi/ui/components/projects/projects.html16
-rw-r--r--testapi/opnfv_testapi/ui/components/projects/projectsController.js66
-rw-r--r--testapi/opnfv_testapi/ui/components/results/result/result.html72
-rw-r--r--testapi/opnfv_testapi/ui/components/results/result/resultController.js22
-rw-r--r--testapi/opnfv_testapi/ui/components/scenarios/modals/customModal.html6
-rw-r--r--testapi/opnfv_testapi/ui/components/scenarios/scenario/scenario.html16
-rw-r--r--testapi/opnfv_testapi/ui/components/scenarios/scenario/scenarioController.js93
-rw-r--r--testapi/opnfv_testapi/ui/components/scenarios/scenarios.html25
-rw-r--r--testapi/opnfv_testapi/ui/components/scenarios/scenariosController.js83
-rw-r--r--testapi/opnfv_testapi/ui/index.html2
-rw-r--r--testapi/opnfv_testapi/ui/package.json1
-rw-r--r--testapi/requirements.txt16
-rw-r--r--testapi/setup.py22
-rw-r--r--testapi/test-requirements.txt12
-rw-r--r--testapi/testapi-client/etc/client.creds3
-rw-r--r--testapi/testapi-client/setup.cfg42
-rw-r--r--testapi/testapi-client/testapiclient/cli/deployresults.py98
-rw-r--r--testapi/testapi-client/testapiclient/cli/pods.py12
-rw-r--r--testapi/testapi-client/testapiclient/cli/projects.py15
-rw-r--r--testapi/testapi-client/testapiclient/cli/results.py97
-rw-r--r--testapi/testapi-client/testapiclient/cli/scenarios.py603
-rw-r--r--testapi/testapi-client/testapiclient/cli/testcases.py114
-rw-r--r--testapi/testapi-client/testapiclient/client/__init__.py0
-rw-r--r--testapi/testapi-client/testapiclient/client/base.py23
-rw-r--r--testapi/testapi-client/testapiclient/client/deploy_results.py28
-rw-r--r--testapi/testapi-client/testapiclient/client/pods.py31
-rw-r--r--testapi/testapi-client/testapiclient/client/projects.py35
-rw-r--r--testapi/testapi-client/testapiclient/client/results.py28
-rw-r--r--testapi/testapi-client/testapiclient/client/scenarios.py177
-rw-r--r--testapi/testapi-client/testapiclient/client/testcases.py36
-rw-r--r--testapi/testapi-client/testapiclient/models/__init__.py0
-rw-r--r--testapi/testapi-client/testapiclient/models/deployresult.py17
-rw-r--r--testapi/testapi-client/testapiclient/models/pods.py6
-rw-r--r--testapi/testapi-client/testapiclient/models/project.py4
-rw-r--r--testapi/testapi-client/testapiclient/models/result.py16
-rw-r--r--testapi/testapi-client/testapiclient/models/scenario.py37
-rw-r--r--testapi/testapi-client/testapiclient/models/testcase.py20
-rw-r--r--testapi/testapi-client/testapiclient/tests/unit/test_app.py50
-rw-r--r--testapi/testapi-client/testapiclient/tests/unit/test_deployresults.py109
-rw-r--r--testapi/testapi-client/testapiclient/tests/unit/test_deployresults_client.py81
-rw-r--r--testapi/testapi-client/testapiclient/tests/unit/test_placeholder.py6
-rw-r--r--testapi/testapi-client/testapiclient/tests/unit/test_pod_client.py89
-rw-r--r--testapi/testapi-client/testapiclient/tests/unit/test_project_client.py111
-rw-r--r--testapi/testapi-client/testapiclient/tests/unit/test_results.py98
-rw-r--r--testapi/testapi-client/testapiclient/tests/unit/test_results_client.py78
-rw-r--r--testapi/testapi-client/testapiclient/tests/unit/test_scenario.py147
-rw-r--r--testapi/testapi-client/testapiclient/tests/unit/test_scenario_client.py104
-rw-r--r--testapi/testapi-client/testapiclient/tests/unit/test_scenario_custom.py88
-rw-r--r--testapi/testapi-client/testapiclient/tests/unit/test_scenario_custom_client.py106
-rw-r--r--testapi/testapi-client/testapiclient/tests/unit/test_scenario_installer.py74
-rw-r--r--testapi/testapi-client/testapiclient/tests/unit/test_scenario_installer_client.py86
-rw-r--r--testapi/testapi-client/testapiclient/tests/unit/test_scenario_project.py90
-rw-r--r--testapi/testapi-client/testapiclient/tests/unit/test_scenario_project_client.py104
-rw-r--r--testapi/testapi-client/testapiclient/tests/unit/test_scenario_score.py42
-rw-r--r--testapi/testapi-client/testapiclient/tests/unit/test_scenario_score_client.py53
-rw-r--r--testapi/testapi-client/testapiclient/tests/unit/test_scenario_trust_indicator.py45
-rw-r--r--testapi/testapi-client/testapiclient/tests/unit/test_scenario_trust_indicator_client.py53
-rw-r--r--testapi/testapi-client/testapiclient/tests/unit/test_scenario_version.py107
-rw-r--r--testapi/testapi-client/testapiclient/tests/unit/test_scenario_version_client.py96
-rw-r--r--testapi/testapi-client/testapiclient/tests/unit/test_testcase_client.py118
-rw-r--r--testapi/testapi-client/testapiclient/tests/unit/test_testcases.py155
-rw-r--r--testapi/testapi-client/testapiclient/tests/unit/utils.py10
-rw-r--r--testapi/testapi-client/testapiclient/utils/clientmanager.py11
-rw-r--r--testapi/testapi-client/testapiclient/utils/command.py11
-rw-r--r--testapi/testapi-client/testapiclient/utils/urlparse.py4
-rw-r--r--testapi/tox.ini7
-rw-r--r--testapi/upper-constraints.txt9
147 files changed, 7834 insertions, 1506 deletions
diff --git a/INFO.yaml b/INFO.yaml
new file mode 100644
index 0000000..c283eca
--- /dev/null
+++ b/INFO.yaml
@@ -0,0 +1,47 @@
+---
+subproject: 'Test Results Collecting and Analyzing (TestResults)'
+project_category: 'Integration & Testing'
+lifecycle_state: 'Incubation'
+subproject_lead: &opnfv_testresults_ptl
+ name: 'SerenaFeng'
+ email: 'feng.xiaowei@zte.com.cn'
+ id: 'serenafeng'
+ company: 'ZTE'
+ timezone: 'China'
+primary_contact: *opnfv_testresults_ptl
+issue_tracking:
+ type: 'jira'
+ url: 'https://jira.opnfv.org/projects/RELENG'
+ key: 'RELENG'
+mailing_list:
+ type: 'mailman2'
+ url: 'opnfv-tech-discuss@lists.opnfv.org'
+ tag: '[testresults]'
+meetings:
+ - type: 'appearin'
+ url: 'https://appear.in/serenafeng'
+ repeats: 'weekly'
+ day: 'Thursday'
+ time: '13:30 UTC'
+committers:
+ - <<: *opnfv_testresults_ptl
+ - name: 'Fatih Degirmenci'
+ company: 'Ericsson'
+ email: 'fatih.degirmenci@ericsson.com'
+ id: 'fdegir'
+ timezone: 'Europe/Stockholm'
+ - name: 'Morgan Richomme'
+ email: 'morgan.richomme@orange.com'
+ company: 'Orange'
+ id: 'mrichomme'
+ timezone: 'Europe/Paris'
+ - name: 'Jose Lausuch'
+ company: 'SUSE'
+ email: 'jalausuch@suse.com'
+ id: 'jose.lausuch'
+ timezone: 'Europe/Madrid'
+ - name: 'Jack Chan'
+ company: 'Huawei'
+ email: 'chenjiankun1@huawei.com'
+ id: 'chenjiankun'
+ timezone: 'China/Shanghai'
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/ci/htmlize/push-doc-artifact.sh b/ci/htmlize/push-doc-artifacts.sh
index e6432d3..e6432d3 100644
--- a/ci/htmlize/push-doc-artifact.sh
+++ b/ci/htmlize/push-doc-artifacts.sh
diff --git a/reporting/html/colorado.html b/reporting/3rd_party/html/colorado.html
index 58cb009..7a7326e 100644
--- a/reporting/html/colorado.html
+++ b/reporting/3rd_party/html/colorado.html
@@ -58,7 +58,7 @@
<span class="image">
<img src="img/projectIcon_functest_250x250.png" alt="" />
</span>
- <a href="functest-colorado.html">
+ <a href="colorado/functest/functest.html">
<h2>Functest</h2>
<div class="content">
<p>Functional testing</p>
diff --git a/reporting/html/danube.html b/reporting/3rd_party/html/danube.html
index e06d6e5..ae8a3ac 100644
--- a/reporting/html/danube.html
+++ b/reporting/3rd_party/html/danube.html
@@ -58,7 +58,7 @@
<span class="image">
<img src="img/projectIcon_functest_250x250.png" alt="" />
</span>
- <a href="functest-danube.html">
+ <a href="danube/functest/functest.html">
<h2>Functest</h2>
<div class="content">
<p>Functional testing</p>
diff --git a/reporting/html/elements.html b/reporting/3rd_party/html/elements.html
index 7b9bb4d..7b9bb4d 100644
--- a/reporting/html/elements.html
+++ b/reporting/3rd_party/html/elements.html
diff --git a/reporting/html/euphrates.html b/reporting/3rd_party/html/euphrates.html
index 1828fc7..e357edc 100644
--- a/reporting/html/euphrates.html
+++ b/reporting/3rd_party/html/euphrates.html
@@ -42,7 +42,7 @@
<span class="image">
<img src="img/projectIcon_functest_250x250.png" alt="" />
</span>
- <a href="functest-euphrates.html">
+ <a href="euphrates/functest/functest.html">
<h2>Functest</h2>
<div class="content">
<p>Functional testing</p>
diff --git a/reporting/html/functest-colorado.html b/reporting/3rd_party/html/fraser.html
index 2fc76d1..65b996c 100644
--- a/reporting/html/functest-colorado.html
+++ b/reporting/3rd_party/html/fraser.html
@@ -1,124 +1,141 @@
-<!DOCTYPE HTML>
-<!--
- Phantom by HTML5 UP
- html5up.net | @ajlkn
- Free for personal and commercial use under the CCA 3.0 license (html5up.net/license)
--->
-<html>
- <head>
- <title>Phantom by HTML5 UP</title>
- <meta charset="utf-8" />
- <meta name="viewport" content="width=device-width, initial-scale=1" />
- <!--[if lte IE 8]><script src="3rd_party/js/ie/html5shiv.js"></script><![endif]-->
- <link rel="stylesheet" href="3rd_party/css/main.css" />
- <!--[if lte IE 9]><link rel="stylesheet" href="3rd_party/css/ie9.css" /><![endif]-->
- <!--[if lte IE 8]><link rel="stylesheet" href="3rd_party/css/ie8.css" /><![endif]-->
- </head>
- <body>
- <!-- Wrapper -->
- <div id="wrapper">
-
- <!-- Header -->
- <header id="header">
- <div class="inner">
-
- <!-- Logo -->
- <a href="index.html" class="logo">
- <span class="symbol"><img src="img/logo.svg" alt="" /></span><span class="title">Phantom</span>
- </a>
-
- <!-- Nav -->
- <!-- <nav>
- <ul>
- <li><a href="#menu">Menu</a></li>
- </ul>
- </nav>
- --->
- </div>
- </header>
-
- <!-- Menu -->
- <!--- <nav id="menu">
- <h2>Menu</h2>
- <ul>
- <li><a href="index.html">Home</a></li>
- <li><a href="colorado.html">Colorado</a></li>
- <li><a href="danube.html">Danube</a></li>
- </ul>
- </nav>
- --->
- <!-- Main -->
- <div id="main">
- <div class="inner">
- <header>
- <h1>Functest reporting</h1>
- </header>
- <section class="tiles">
- <article class="style5">
- <span class="image">
- <img src="img/pic05.jpg" alt="" />
- </span>
- <a href="colorado/functest/status-apex.html">
- <h2>Status</h2>
- <div class="content">
- <p>Scenario status</p>
- </div>
- </a>
- </article>
- <article class="style2">
- <span class="image">
- <img src="img/pic02.jpg" alt="" />
- </span>
- <a href="colorado/functest/vims-apex.html">
- <h2>vIMS</h2>
- <div class="content">
- <p>Virtual IMS</p>
- </div>
- </a>
- </article>
- <article class="style3">
- <span class="image">
- <img src="img/pic03.jpg" alt="" />
- </span>
- <a href="colorado/functest/tempest-apex.html">
- <h2>Tempest</h2>
- <div class="content">
- <p>Tempest OpenStack suite</p>
- </div>
- </a>
- </article>
- </section>
- </div>
- </div>
-
- <!-- Footer -->
- <footer id="footer">
- <div class="inner">
- <section>
- <h2>OPNFV Testing Working group</h2>
- </section>
- <section>
- <h2>Follow</h2>
- <ul class="icons">
- <li><a href="https://twitter.com/opnfv" class="icon style2 fa-twitter"><span class="label">Twitter</span></a></li>
- <li><a href="http://git.opnfv.org" class="icon style2 fa-github"><span class="label">GitHub</span></a></li>
- <li><a href="mailto:test-wg@list.opnfv.org" class="icon style2 fa-envelope-o"><span class="label">Email</span></a></li>
- </ul>
- </section>
- <ul class="copyright">
- <li>&copy; Untitled. All rights reserved</li><li>Design: <a href="http://html5up.net">HTML5 UP</a></li>
- </ul>
- </div>
- </footer>
-
- </div>
-
- <!-- Scripts -->
- <script src="3rd_party/js/jquery.min.js"></script>
- <script src="3rd_party/js/skel.min.js"></script>
- <script src="3rd_party/js/util.js"></script>
- <!--[if lte IE 8]><script src="3rd_party/js/ie/respond.min.js"></script><![endif]-->
- <script src="3rd_party/js/main.js"></script>
-
- </body>
-</html>
+<!DOCTYPE HTML>
+<!--
+ Phantom by HTML5 UP
+ html5up.net | @ajlkn
+ Free for personal and commercial use under the CCA 3.0 license (html5up.net/license)
+-->
+<html>
+ <head>
+ <title>Phantom by HTML5 UP</title>
+ <meta charset="utf-8" />
+ <meta name="viewport" content="width=device-width, initial-scale=1" />
+ <!--[if lte IE 8]><script src="3rd_party/js/ie/html5shiv.js"></script><![endif]-->
+ <link rel="stylesheet" href="3rd_party/css/main.css" />
+ <!--[if lte IE 9]><link rel="stylesheet" href="3rd_party/css/ie9.css" /><![endif]-->
+ <!--[if lte IE 8]><link rel="stylesheet" href="3rd_party/css/ie8.css" /><![endif]-->
+ </head>
+ <body>
+ <!-- Wrapper -->
+ <div id="wrapper">
+
+ <!-- Header -->
+ <header id="header">
+ <div class="inner">
+
+ <!-- Logo -->
+ <a href="index.html" class="logo">
+ <span class="symbol"><img src="img/logo.svg" alt="" /></span><span class="title">Phantom</span>
+ </a>
+
+ </div>
+ </header>
+
+ <!-- Menu -->
+ <!-- Main -->
+ <div id="main">
+ <div class="inner">
+ <header>
+ <h1>Fraser reporting</h1>
+ </header>
+ <section class="tiles">
+ <article class="style3">
+ <span class="image">
+ <img src="img/projectIcon_functest_250x250.png" alt="" />
+ </span>
+ <a href="fraser/functest/functest.html">
+ <h2>Functest</h2>
+ <div class="content">
+ <p>Functional testing</p>
+ </div>
+ </a>
+ </article>
+ <article class="style2">
+ <span class="image">
+ <img src="img/projectIcon_yardstick_250x250.png" alt="" />
+ </span>
+ <a href="fraser/yardstick/status-apex.html">
+ <h2>Yardstick</h2>
+ <div class="content">
+ <p>Qualification and performance testing</p>
+ </div>
+ </a>
+ </article>
+ <article class="style4">
+ <span class="image">
+ <img src="img/projectIcon_storperf_250x250.png" alt="" />
+ </span>
+ <a href="fraser/storperf/status-apex.html">
+ <h2>Storperf</h2>
+ <div class="content">
+ <p>Storage testing</p>
+ </div>
+ </a>
+ </article>
+ <article class="style5">
+ <span class="image">
+ <img src="img/projectIcon_vsperf_250x250.png" alt="" />
+ </span>
+ <a href="fraser/vsperf/reporting.html">
+ <h2>Vsperf</h2>
+ <div class="content">
+ <p>Virtual switch testing</p>
+ </div>
+ </a>
+ </article>
+ <article class="style1">
+ <span class="image">
+ <img src="img/projectIcon_qtip_250x250.png" alt="" />
+ </span>
+ <a href="fraser/qtip/status-apex.html">
+ <h2>Qtip</h2>
+ <div class="content">
+ <p>Benchmark as a service</p>
+ </div>
+ </a>
+ </article>
+ <article class="style6">
+ <span class="image">
+ <img src="img/projectIcon_bottlenecks_250x250.png" alt="" />
+ </span>
+ <a href="fraser/bottlenecks/status-apex.html">
+ <h2>Bottlenecks</h2>
+ <div class="content">
+ <p>Bottleneck finder</p>
+ </div>
+ </a>
+ </article>
+ </section>
+ </div>
+ </div>
+
+ <!-- Footer -->
+ <footer id="footer">
+ <div class="inner">
+ <section>
+ <h2>OPNFV Testing Working group</h2>
+ </section>
+ <section>
+ <h2>Follow</h2>
+ <ul class="icons">
+ <li><a href="https://twitter.com/opnfv" class="icon style2 fa-twitter"><span class="label">Twitter</span></a></li>
+ <li><a href="http://git.opnfv.org" class="icon style2 fa-github"><span class="label">GitHub</span></a></li>
+ <li><a href="mailto:test-wg@list.opnfv.org" class="icon style2 fa-envelope-o"><span class="label">Email</span></a></li>
+ </ul>
+ </section>
+ <ul class="copyright">
+ <li>&copy; Untitled. All rights reserved</li><li>Design: <a href="http://html5up.net">HTML5 UP</a></li>
+ </ul>
+ </div>
+ </footer>
+
+ </div>
+
+ <!-- Scripts -->
+ <script src="3rd_party/js/jquery.min.js"></script>
+ <script src="3rd_party/js/skel.min.js"></script>
+ <script src="3rd_party/js/util.js"></script>
+ <!--[if lte IE 8]><script src="3rd_party/js/ie/respond.min.js"></script><![endif]-->
+ <script src="3rd_party/js/main.js"></script>
+
+ </body>
+</html>
diff --git a/reporting/html/functest-euphrates.html b/reporting/3rd_party/html/functest.html
index c203e61..d5f78c5 100644
--- a/reporting/html/functest-euphrates.html
+++ b/reporting/3rd_party/html/functest.html
@@ -9,10 +9,7 @@
<title>Phantom by HTML5 UP</title>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1" />
- <!--[if lte IE 8]><script src="3rd_party/js/ie/html5shiv.js"></script><![endif]-->
- <link rel="stylesheet" href="3rd_party/css/main.css" />
- <!--[if lte IE 9]><link rel="stylesheet" href="3rd_party/css/ie9.css" /><![endif]-->
- <!--[if lte IE 8]><link rel="stylesheet" href="3rd_party/css/ie8.css" /><![endif]-->
+ <link rel="stylesheet" href="../../3rd_party/css/main.css" />
</head>
<body>
<!-- Wrapper -->
@@ -24,7 +21,9 @@
<!-- Logo -->
<a href="index.html" class="logo">
- <span class="symbol"><img src="img/logo.svg" alt="" /></span><span class="title">Phantom</span>
+ <span class="symbol"><img src="../../img/logo.svg" alt="" />
+ </span>
+ <span class="title">Functest</span>
</a>
</div>
@@ -41,9 +40,9 @@
<section class="tiles">
<article class="style5">
<span class="image">
- <img src="img/pic05.jpg" alt="" />
+ <img src="../../img/pic05.jpg" alt="" />
</span>
- <a href="euphrates/functest/status-apex.html">
+ <a href="status-apex.html">
<h2>Status</h2>
<div class="content">
<p>Scenario status</p>
@@ -52,9 +51,9 @@
</article>
<article class="style2">
<span class="image">
- <img src="img/pic02.jpg" alt="" />
+ <img src="../../img/pic02.jpg" alt="" />
</span>
- <a href="euphrates/functest/vims-apex.html">
+ <a href="vims-apex.html">
<h2>vIMS</h2>
<div class="content">
<p>Virtual IMS</p>
@@ -63,9 +62,9 @@
</article>
<article class="style3">
<span class="image">
- <img src="img/pic03.jpg" alt="" />
+ <img src="../../img/pic03.jpg" alt="" />
</span>
- <a href="euphrates/functest/tempest-apex.html">
+ <a href="tempest-apex.html">
<h2>Tempest</h2>
<div class="content">
<p>Tempest OpenStack suite</p>
@@ -99,11 +98,11 @@
</div>
<!-- Scripts -->
- <script src="3rd_party/js/jquery.min.js"></script>
- <script src="3rd_party/js/skel.min.js"></script>
- <script src="3rd_party/js/util.js"></script>
+ <script src="../../3rd_party/js/jquery.min.js"></script>
+ <script src="../../3rd_party/js/skel.min.js"></script>
+ <script src="../../3rd_party/js/util.js"></script>
<!--[if lte IE 8]><script src="3rd_party/js/ie/respond.min.js"></script><![endif]-->
- <script src="3rd_party/js/main.js"></script>
+ <script src="../../3rd_party/js/main.js"></script>
</body>
</html>
diff --git a/reporting/html/functest-danube.html b/reporting/3rd_party/html/gambia.html
index ac99cb0..d5f6fcd 100644
--- a/reporting/html/functest-danube.html
+++ b/reporting/3rd_party/html/gambia.html
@@ -27,63 +27,80 @@
<span class="symbol"><img src="img/logo.svg" alt="" /></span><span class="title">Phantom</span>
</a>
- <!-- Nav -->
- <!-- <nav>
- <ul>
- <li><a href="#menu">Menu</a></li>
- </ul>
- </nav>
- --->
</div>
</header>
<!-- Menu -->
- <!--- <nav id="menu">
- <h2>Menu</h2>
- <ul>
- <li><a href="index.html">Home</a></li>
- <li><a href="colorado.html">Colorado</a></li>
- <li><a href="danube.html">Danube</a></li>
- </ul>
- </nav>
- --->
<!-- Main -->
<div id="main">
<div class="inner">
<header>
- <h1>Functest reporting</h1>
+ <h1>Gambia reporting</h1>
</header>
<section class="tiles">
- <article class="style5">
+ <article class="style3">
<span class="image">
- <img src="img/pic05.jpg" alt="" />
+ <img src="img/projectIcon_functest_250x250.png" alt="" />
</span>
- <a href="danube/functest/status-apex.html">
- <h2>Status</h2>
+ <a href="gambia/functest/functest.html">
+ <h2>Functest</h2>
<div class="content">
- <p>Scenario status</p>
+ <p>Functional testing</p>
</div>
</a>
</article>
<article class="style2">
<span class="image">
- <img src="img/pic02.jpg" alt="" />
+ <img src="img/projectIcon_yardstick_250x250.png" alt="" />
</span>
- <a href="danube/functest/vims-apex.html">
- <h2>vIMS</h2>
+ <a href="gambia/yardstick/status-apex.html">
+ <h2>Yardstick</h2>
<div class="content">
- <p>Virtual IMS</p>
+ <p>Qualification and performance testing</p>
</div>
</a>
</article>
- <article class="style3">
+ <article class="style4">
+ <span class="image">
+ <img src="img/projectIcon_storperf_250x250.png" alt="" />
+ </span>
+ <a href="gambia/storperf/status-apex.html">
+ <h2>Storperf</h2>
+ <div class="content">
+ <p>Storage testing</p>
+ </div>
+ </a>
+ </article>
+ <article class="style5">
+ <span class="image">
+ <img src="img/projectIcon_vsperf_250x250.png" alt="" />
+ </span>
+ <a href="gambia/vsperf/reporting.html">
+ <h2>Vsperf</h2>
+ <div class="content">
+ <p>Virtual switch testing</p>
+ </div>
+ </a>
+ </article>
+ <article class="style1">
+ <span class="image">
+ <img src="img/projectIcon_qtip_250x250.png" alt="" />
+ </span>
+ <a href="gambia/qtip/status-apex.html">
+ <h2>Qtip</h2>
+ <div class="content">
+ <p>Benchmark as a service</p>
+ </div>
+ </a>
+ </article>
+ <article class="style6">
<span class="image">
- <img src="img/pic03.jpg" alt="" />
+ <img src="img/projectIcon_bottlenecks_250x250.png" alt="" />
</span>
- <a href="danube/functest/tempest-apex.html">
- <h2>Tempest</h2>
+ <a href="gambia/bottlenecks/status-apex.html">
+ <h2>Bottlenecks</h2>
<div class="content">
- <p>Tempest OpenStack suite</p>
+ <p>Bottleneck finder</p>
</div>
</a>
</article>
diff --git a/reporting/html/generic.html b/reporting/3rd_party/html/generic.html
index 39273da..39273da 100644
--- a/reporting/html/generic.html
+++ b/reporting/3rd_party/html/generic.html
diff --git a/reporting/html/index.html b/reporting/3rd_party/html/index.html
index 22d7078..9165250 100644
--- a/reporting/html/index.html
+++ b/reporting/3rd_party/html/index.html
@@ -43,40 +43,29 @@
<h1>OPNFV Testing group reporting</h1>
</header>
<section class="tiles">
- <article class="style3">
+ <article class="style4">
<span class="image">
- <img src="img/colorado.jpg" alt="" />
+ <img src="img/fraser.jpg" alt="" />
</span>
- <a href="colorado.html">
- <h2>Colorado</h2>
+ <a href="fraser.html">
+ <h2>Fraser</h2>
<div class="content">
- <p>Colorado 1.0 (22/09/2016)</p>
+ <p>Fraser (ETA 04/2018)</p>
</div>
</a>
</article>
- <article class="style2">
- <span class="image">
- <img src="img/danube.jpg" alt="" />
- </span>
- <a href="danube.html">
- <h2>Danube</h2>
- <div class="content">
- <p>Danube 1.0 (22/03/2017)</p>
- </div>
- </a>
- </article>
- <article class="style4">
+ <article class="style6">
<span class="image">
- <img src="img/euphrates.jpg" alt="" />
+ <img src="img/gambia.jpg" alt="" />
</span>
- <a href="euphrates.html">
- <h2>Euphrates</h2>
+ <a href="gambia.html">
+ <h2>Gambia</h2>
<div class="content">
- <p>Euphrates (ETA 10/2017)</p>
+ <p>Gambia (ETA 11/2018)</p>
</div>
</a>
</article>
- <article class="style6">
+ <article class="style5">
<span class="image">
<img src="img/misc-npc-letterblock-m-800px.png" alt="" />
</span>
diff --git a/reporting/html/master.html b/reporting/3rd_party/html/master.html
index 312e8e6..5d4f916 100644
--- a/reporting/html/master.html
+++ b/reporting/3rd_party/html/master.html
@@ -58,7 +58,7 @@
<span class="image">
<img src="img/projectIcon_functest_250x250.png" alt="" />
</span>
- <a href="functest-master.html">
+ <a href="master/functest/functest.html">
<h2>Functest</h2>
<div class="content">
<p>Functional testing</p>
diff --git a/reporting/api/conf.py b/reporting/api/conf.py
index 5897d4f..d0023e0 100644
--- a/reporting/api/conf.py
+++ b/reporting/api/conf.py
@@ -1 +1,5 @@
base_url = 'http://testresults.opnfv.org/test/api/v1'
+
+versions = ['master', 'fraser', 'gambia']
+
+period = 10
diff --git a/reporting/api/extension/__init__.py b/reporting/api/extension/__init__.py
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/reporting/api/extension/__init__.py
diff --git a/reporting/api/extension/client.py b/reporting/api/extension/client.py
new file mode 100644
index 0000000..03371fd
--- /dev/null
+++ b/reporting/api/extension/client.py
@@ -0,0 +1,15 @@
+from tornado.simple_httpclient import SimpleAsyncHTTPClient
+from tornado.log import gen_log
+
+
+class NoQueueTimeoutHTTPClient(SimpleAsyncHTTPClient):
+ def fetch_impl(self, request, callback):
+ key = object()
+
+ self.queue.append((key, request, callback))
+ self.waiting[key] = (request, callback, None)
+
+ self._process_queue()
+
+ if self.queue:
+ gen_log.debug("max_clients limit reached, request queued.")
diff --git a/reporting/api/handlers/scenarios.py b/reporting/api/handlers/scenarios.py
new file mode 100644
index 0000000..70447c7
--- /dev/null
+++ b/reporting/api/handlers/scenarios.py
@@ -0,0 +1,27 @@
+from tornado.web import asynchronous
+from tornado.gen import coroutine
+from tornado.escape import json_encode
+
+from api.handlers import BaseHandler
+from api.service.scenario import ScenarioTableResult
+
+
+class Result(BaseHandler):
+ @asynchronous
+ @coroutine
+ def get(self):
+ self._set_header()
+
+ scenario = self.get_argument('scenario', None)
+ version = self.get_argument('version', 'master')
+ installer = self.get_argument('installer', None)
+ iteration = int(self.get_argument('iteration', 10))
+
+ yield self._get_scenario_data(scenario, version, installer, iteration)
+
+ @coroutine
+ def _get_scenario_data(self, scenario, version, installer, iteration):
+ results = ScenarioTableResult(scenario, version, installer, iteration)
+ result = yield results.get()
+ self.write(json_encode(result))
+ self.finish()
diff --git a/reporting/api/server.py b/reporting/api/server.py
index e340b01..461e6d5 100644
--- a/reporting/api/server.py
+++ b/reporting/api/server.py
@@ -12,6 +12,7 @@ from tornado.options import define
from tornado.options import options
from api.urls import mappings
+from api.service.result import ResultCache
define("port", default=8000, help="run on the given port", type=int)
@@ -20,7 +21,12 @@ def main():
tornado.options.parse_command_line()
application = tornado.web.Application(mappings)
application.listen(options.port)
- tornado.ioloop.IOLoop.current().start()
+
+ tornado.ioloop.PeriodicCallback(ResultCache.update, 1800000).start()
+
+ ioloop = tornado.ioloop.IOLoop.current()
+ ioloop.call_later(1000, ResultCache.update())
+ ioloop.start()
if __name__ == "__main__":
diff --git a/reporting/api/service/__init__.py b/reporting/api/service/__init__.py
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/reporting/api/service/__init__.py
diff --git a/reporting/api/service/result.py b/reporting/api/service/result.py
new file mode 100644
index 0000000..fa6553c
--- /dev/null
+++ b/reporting/api/service/result.py
@@ -0,0 +1,90 @@
+import json
+import logging
+from collections import defaultdict
+
+from tornado.gen import coroutine
+from tornado.gen import Return
+from tornado.httpclient import AsyncHTTPClient
+
+from api import conf as consts
+from api.extension.client import NoQueueTimeoutHTTPClient
+
+LOG = logging.getLogger(__name__)
+AsyncHTTPClient.configure(NoQueueTimeoutHTTPClient)
+
+
+class Result(object):
+
+ def __init__(self):
+ self._url = '{}/results?period={}&version={}&page={}'
+ self._client = AsyncHTTPClient()
+ self._result = defaultdict(list)
+
+ @property
+ @coroutine
+ def result(self):
+ if not self._result:
+ yield self.update_results()
+ raise Return(self._result)
+
+ @coroutine
+ def update_results(self):
+ LOG.info('start update results')
+
+ for version in consts.versions:
+ yield self._update_version_result(version)
+
+ LOG.info('results update finished')
+
+ @coroutine
+ def _update_version_result(self, version):
+ total_page = yield self._get_total_page(version)
+
+ responses = yield self._fetch_results(version, total_page)
+
+ self._update_version_dict(version, responses)
+
+ @coroutine
+ def _fetch_results(self, version, total_page):
+ urls = [self._url.format(consts.base_url, consts.period, version, i)
+ for i in range(1, total_page + 1)]
+ responses = yield [self._client.fetch(url) for url in urls]
+ raise Return(responses)
+
+ @coroutine
+ def _get_total_page(self, version):
+ url = self._url.format(consts.base_url, consts.period, version, 1)
+ response = yield self._client.fetch(url)
+ raise Return(json.loads(response.body)['pagination']['total_pages'])
+
+ def _update_version_dict(self, version, responses):
+ for response in responses:
+ results = json.loads(response.body)['results']
+ for result in results:
+ data = {k: v for k, v in result.items() if k != 'details'}
+ self._result[version].append(data)
+
+
+class ResultCache(Result):
+
+ @classmethod
+ @coroutine
+ def update(cls):
+ cls._check()
+
+ yield cls.cache.update_results()
+
+ @classmethod
+ @coroutine
+ def get(cls, version):
+ cls._check()
+
+ result = yield cls.cache.result
+ raise Return(result[version])
+
+ @classmethod
+ def _check(cls):
+ try:
+ cls.cache
+ except AttributeError:
+ cls.cache = cls()
diff --git a/reporting/api/service/scenario.py b/reporting/api/service/scenario.py
new file mode 100644
index 0000000..f9e2a91
--- /dev/null
+++ b/reporting/api/service/scenario.py
@@ -0,0 +1,133 @@
+import abc
+from collections import defaultdict
+
+import six
+from tornado.gen import coroutine
+from tornado.gen import Return
+
+from api.service.result import ResultCache
+
+PROJECTS = ['fastdatastacks', 'barometer', 'sfc', 'sdnvpn', 'doctor', 'parser']
+
+
+def _set(key, llist):
+ return set(x[key] for x in llist)
+
+
+def _filter(key, value, llist):
+ return filter(lambda x: x[key] == value, llist)
+
+
+class ScenarioTableResult(object):
+
+ def __init__(self, scenario, version, installer, iteration):
+ self.scenario = scenario
+ self.version = version
+ self.installer = installer
+ self.iteration = iteration
+
+ @coroutine
+ def get(self):
+ results = yield ResultCache.get(self.version)
+ results = self._filter_result(results)
+ results = self._struct_result(results)
+
+ raise Return(results)
+
+ def _filter_result(self, results):
+ results = [x for x in results if x['build_tag']]
+ if self.installer:
+ results = _filter('installer', self.installer, results)
+ if self.scenario:
+ results = _filter('scenario', self.scenario, results)
+ return results
+
+ def _struct_result(self, results):
+
+ return {
+ s: self._struct_scenario(_filter('scenario', s, results))
+ for s in _set('scenario', results)
+ }
+
+ def _struct_scenario(self, data):
+ return sorted([
+ HandlerFacade.get_result(b, _filter('build_tag', b, data))
+ for b in _set('build_tag', data)
+ ], key=lambda x: x['date'], reverse=True)[:self.iteration]
+
+
+class HandlerFacade(object):
+
+ @classmethod
+ def get_result(cls, index, data):
+ if not data:
+ return {}
+
+ cls._change_name_to_functest(data)
+ data = cls._sort_by_start_date(data)
+
+ return {
+ 'id': index,
+ 'date': data[0]['start_date'],
+ 'version': data[0]['version'],
+ 'installer': data[0]['installer'],
+ 'projects': cls._get_projects_data(data)
+ }
+
+ @classmethod
+ def _sort_by_start_date(cls, data):
+ return sorted(data, key=lambda x: x['start_date'])
+
+ @classmethod
+ def _get_projects_data(cls, data):
+
+ return {
+ p: HANDLER_MAP[p](_filter('project_name', p, data)).struct()
+ for p in _set('project_name', data)
+ }
+
+ @classmethod
+ def _change_name_to_functest(cls, data):
+ for ele in data:
+ if ele['project_name'] in PROJECTS:
+ ele['project_name'] = 'functest'
+
+
+@six.add_metaclass(abc.ABCMeta)
+class ProjectHandler(object):
+
+ def __init__(self, data):
+ self.data = data
+
+ def struct(self):
+ return self._struct_project_data()
+
+ def _struct_project_data(self):
+ return {
+ 'gating': self._gating()
+ }
+
+ @abc.abstractmethod
+ def _gating(self):
+ pass
+
+
+class DefaultHandler(ProjectHandler):
+
+ def _struct_project_data(self):
+ return {}
+
+ def _gating(self):
+ pass
+
+
+class FunctestHandler(ProjectHandler):
+
+ def _gating(self):
+ if all([x['criteria'] == 'PASS' for x in self.data]):
+ return 'PASS'
+ else:
+ return 'FAIL'
+
+
+HANDLER_MAP = defaultdict(lambda: DefaultHandler, functest=FunctestHandler)
diff --git a/reporting/api/urls.py b/reporting/api/urls.py
index a5228b2..34f61d8 100644
--- a/reporting/api/urls.py
+++ b/reporting/api/urls.py
@@ -9,6 +9,7 @@
from api.handlers import landing
from api.handlers import projects
from api.handlers import testcases
+from api.handlers import scenarios
mappings = [
(r"/landing-page/filters", landing.FiltersHandler),
@@ -16,5 +17,7 @@ mappings = [
(r"/projects-page/projects", projects.Projects),
(r"/projects/([^/]+)/cases", testcases.TestCases),
- (r"/projects/([^/]+)/cases/([^/]+)", testcases.TestCase)
+ (r"/projects/([^/]+)/cases/([^/]+)", testcases.TestCase),
+
+ (r"/scenarios/results", scenarios.Result)
]
diff --git a/reporting/css/default.css b/reporting/css/default.css
index e32fa5f..686e886 100644
--- a/reporting/css/default.css
+++ b/reporting/css/default.css
@@ -26,6 +26,7 @@
width: 100%;
background-color: #0095a2
}
+
.panel-default > .panel-heading h4 {
color: white;
}
@@ -55,7 +56,7 @@ td{
background-color: #0095a2;
}
-h1 {
+h1 {
display: block;
font-size: 2em;
margin-top: 0.67em;
@@ -191,4 +192,3 @@ h2 {
position:relative;
top:1px;
}
-
diff --git a/reporting/docker/reporting.sh b/reporting/docker/reporting.sh
index 2cb438d..f3f3d50 100755
--- a/reporting/docker/reporting.sh
+++ b/reporting/docker/reporting.sh
@@ -3,7 +3,7 @@
export PYTHONPATH="${PYTHONPATH}:./reporting"
export CONFIG_REPORTING_YAML=./reporting/reporting.yaml
-declare -a versions=(euphrates danube master)
+declare -a versions=(gambia fraser master)
declare -a projects=(functest storperf yardstick qtip vsperf bottlenecks)
project=$1
@@ -21,7 +21,7 @@ done
# copy images, js, css, 3rd_party
cp -Rf 3rd_party display
cp -Rf css display
-cp -Rf html/* display
+cp -Rf 3rd_party/html/* display
cp -Rf img display
cp -Rf js display
diff --git a/reporting/html/functest-master.html b/reporting/html/functest-master.html
deleted file mode 100644
index 4b1f763..0000000
--- a/reporting/html/functest-master.html
+++ /dev/null
@@ -1,124 +0,0 @@
-<!DOCTYPE HTML>
-<!--
- Phantom by HTML5 UP
- html5up.net | @ajlkn
- Free for personal and commercial use under the CCA 3.0 license (html5up.net/license)
--->
-<html>
- <head>
- <title>Phantom by HTML5 UP</title>
- <meta charset="utf-8" />
- <meta name="viewport" content="width=device-width, initial-scale=1" />
- <!--[if lte IE 8]><script src="3rd_party/js/ie/html5shiv.js"></script><![endif]-->
- <link rel="stylesheet" href="3rd_party/css/main.css" />
- <!--[if lte IE 9]><link rel="stylesheet" href="3rd_party/css/ie9.css" /><![endif]-->
- <!--[if lte IE 8]><link rel="stylesheet" href="3rd_party/css/ie8.css" /><![endif]-->
- </head>
- <body>
- <!-- Wrapper -->
- <div id="wrapper">
-
- <!-- Header -->
- <header id="header">
- <div class="inner">
-
- <!-- Logo -->
- <a href="index.html" class="logo">
- <span class="symbol"><img src="img/logo.svg" alt="" /></span><span class="title">Phantom</span>
- </a>
-
- <!-- Nav -->
- <!-- <nav>
- <ul>
- <li><a href="#menu">Menu</a></li>
- </ul>
- </nav>
- --->
- </div>
- </header>
-
- <!-- Menu -->
- <!--- <nav id="menu">
- <h2>Menu</h2>
- <ul>
- <li><a href="index.html">Home</a></li>
- <li><a href="colorado.html">Colorado</a></li>
- <li><a href="danube.html">Danube</a></li>
- </ul>
- </nav>
- --->
- <!-- Main -->
- <div id="main">
- <div class="inner">
- <header>
- <h1>Functest reporting</h1>
- </header>
- <section class="tiles">
- <article class="style5">
- <span class="image">
- <img src="img/pic05.jpg" alt="" />
- </span>
- <a href="master/functest/status-apex.html">
- <h2>Status</h2>
- <div class="content">
- <p>Scenario status</p>
- </div>
- </a>
- </article>
- <article class="style2">
- <span class="image">
- <img src="img/pic02.jpg" alt="" />
- </span>
- <a href="master/functest/vims-apex.html">
- <h2>vIMS</h2>
- <div class="content">
- <p>Virtual IMS</p>
- </div>
- </a>
- </article>
- <article class="style3">
- <span class="image">
- <img src="img/pic03.jpg" alt="" />
- </span>
- <a href="master/functest/tempest-apex.html">
- <h2>Tempest</h2>
- <div class="content">
- <p>Tempest OpenStack suite</p>
- </div>
- </a>
- </article>
- </section>
- </div>
- </div>
-
- <!-- Footer -->
- <footer id="footer">
- <div class="inner">
- <section>
- <h2>OPNFV Testing Working group</h2>
- </section>
- <section>
- <h2>Follow</h2>
- <ul class="icons">
- <li><a href="https://twitter.com/opnfv" class="icon style2 fa-twitter"><span class="label">Twitter</span></a></li>
- <li><a href="http://git.opnfv.org" class="icon style2 fa-github"><span class="label">GitHub</span></a></li>
- <li><a href="mailto:test-wg@list.opnfv.org" class="icon style2 fa-envelope-o"><span class="label">Email</span></a></li>
- </ul>
- </section>
- <ul class="copyright">
- <li>&copy; Untitled. All rights reserved</li><li>Design: <a href="http://html5up.net">HTML5 UP</a></li>
- </ul>
- </div>
- </footer>
-
- </div>
-
- <!-- Scripts -->
- <script src="3rd_party/js/jquery.min.js"></script>
- <script src="3rd_party/js/skel.min.js"></script>
- <script src="3rd_party/js/util.js"></script>
- <!--[if lte IE 8]><script src="3rd_party/js/ie/respond.min.js"></script><![endif]-->
- <script src="3rd_party/js/main.js"></script>
-
- </body>
-</html>
diff --git a/reporting/img/fraser.jpg b/reporting/img/fraser.jpg
new file mode 100644
index 0000000..8bc6b51
--- /dev/null
+++ b/reporting/img/fraser.jpg
Binary files differ
diff --git a/reporting/img/gambia.jpg b/reporting/img/gambia.jpg
new file mode 100644
index 0000000..fd91d11
--- /dev/null
+++ b/reporting/img/gambia.jpg
Binary files differ
diff --git a/reporting/js/gauge.js b/reporting/js/gauge.js
index 4cad16c..a9842e5 100644
--- a/reporting/js/gauge.js
+++ b/reporting/js/gauge.js
@@ -28,7 +28,9 @@ var gauge = function(container) {
labelFormat : d3.format(',g'),
labelInset : 10,
- arcColorFn : d3.interpolateHsl(d3.rgb('#ff0000'), d3.rgb('#00ff00'))
+ arcColorFn : d3.scale.quantile()
+ .domain([0, , 0.6, 0.8, 1])
+ .range([d3.rgb('#ff0000'),d3.rgb('#ffcc00'),d3.rgb('#00ff00')])
};
diff --git a/reporting/pages/app/index.html b/reporting/pages/app/index.html
index 843a623..6ef1d02 100644
--- a/reporting/pages/app/index.html
+++ b/reporting/pages/app/index.html
@@ -87,6 +87,7 @@
<script src="scripts/controllers/auth.controller.js"></script>
<script src="scripts/controllers/admin.controller.js"></script>
<script src="scripts/controllers/main.controller.js"></script>
+ <script src="scripts/controllers/gating.controller.js"></script>
<script src="scripts/controllers/testvisual.controller.js"></script>
<!-- endbuild -->
diff --git a/reporting/pages/app/scripts/config.router.js b/reporting/pages/app/scripts/config.router.js
index d3724b7..45a6997 100644
--- a/reporting/pages/app/scripts/config.router.js
+++ b/reporting/pages/app/scripts/config.router.js
@@ -17,11 +17,11 @@ angular.module('opnfvApp')
]).config(['$stateProvider', '$urlRouterProvider',
function($stateProvider, $urlRouterProvider) {
- $urlRouterProvider.otherwise('/landingpage/table');
+ $urlRouterProvider.otherwise('/home/gating');
$stateProvider
- .state('landingpage', {
- url: "/landingpage",
+ .state('home', {
+ url: "/home",
controller: 'MainController',
templateUrl: "views/main.html",
data: { pageTitle: '首页', specialClass: 'landing-page' },
@@ -33,7 +33,7 @@ angular.module('opnfvApp')
}]
}
})
- .state('landingpage.table', {
+ .state('home.table', {
url: "/table",
controller: 'TableController',
templateUrl: "views/commons/table.html",
@@ -47,6 +47,19 @@ angular.module('opnfvApp')
}]
}
})
+ .state('home.gating', {
+ url: "/gating",
+ controller: 'GatingController',
+ templateUrl: "views/gating.html",
+ data: { pageTitle: 'OPNFV Release Gating Page', specialClass: 'landing-page' },
+ resolve: {
+ controller: ['$ocLazyLoad', function($ocLazyLoad) {
+ return $ocLazyLoad.load([
+
+ ])
+ }]
+ }
+ })
.state('select', {
url: '/select',
templateUrl: "views/testcase.html",
diff --git a/reporting/pages/app/scripts/controllers/gating.controller.js b/reporting/pages/app/scripts/controllers/gating.controller.js
new file mode 100644
index 0000000..52b381d
--- /dev/null
+++ b/reporting/pages/app/scripts/controllers/gating.controller.js
@@ -0,0 +1,119 @@
+'use strict';
+
+angular.module('opnfvApp')
+ .controller('GatingController', ['$scope', '$state', '$stateParams', 'TableFactory', function($scope, $state, $stateParams, TableFactory) {
+
+ init();
+
+ function init() {
+ $scope.goTest = goTest;
+ $scope.goLogin = goLogin;
+
+ $scope.scenarios = {};
+
+ $scope.scenarioList = _toSelectList(['all']);
+ $scope.versionList = _toSelectList(['master', 'fraser', 'gambia']);
+ $scope.installerList = _toSelectList(['all', 'apex', 'compass', 'daisy', 'fuel', 'joid']);
+ $scope.iterationList = _toSelectList([10, 20, 30]);
+
+ $scope.selectScenario = 'all';
+ $scope.selectVersion = 'master';
+ $scope.selectInstaller = 'all';
+ $scope.selectIteration = 10;
+
+ $scope.ScenarioConfig = {
+ create: true,
+ valueField: 'title',
+ labelField: 'title',
+ delimiter: '|',
+ maxItems: 1,
+ placeholder: 'Scenario',
+ onChange: function(value) {
+ $scope.selectScenario = value;
+ }
+ }
+
+ $scope.VersionConfig = {
+ create: true,
+ valueField: 'title',
+ labelField: 'title',
+ delimiter: '|',
+ maxItems: 1,
+ placeholder: 'Version',
+ onChange: function(value) {
+ $scope.selectVersion = value;
+ getScenarioResult();
+ }
+ }
+
+ $scope.InstallerConfig = {
+ create: true,
+ valueField: 'title',
+ labelField: 'title',
+ delimiter: '|',
+ maxItems: 1,
+ placeholder: 'Installer',
+ onChange: function(value) {
+ $scope.selectInstaller = value;
+ getScenarioResult();
+ }
+ }
+
+ $scope.IterationConfig = {
+ create: true,
+ valueField: 'title',
+ labelField: 'title',
+ delimiter: '|',
+ maxItems: 1,
+ placeholder: 'Iteration',
+ onChange: function(value) {
+ $scope.selectIteration = value;
+ getScenarioResult();
+ }
+ }
+ getScenarioResult();
+ }
+
+ function getScenarioResult(){
+ _getScenarioResult($scope.selectVersion, $scope.selectInstaller, $scope.selectIteration);
+ }
+
+ function _getScenarioResult(version, installer, iteration){
+ var data = {
+ 'version': version,
+ 'iteration': iteration
+ }
+
+ if(installer != 'all'){
+ data['installer'] = installer;
+ }
+
+ TableFactory.getScenarioResult().get(data).$promise.then(function(resp){
+ $scope.scenarios = resp;
+ _concat($scope.scenarioList, _toSelectList(Object.keys(resp)));
+ }, function(err){
+ });
+ }
+
+ function _concat(aList, bList){
+ angular.forEach(bList, function(ele){
+ aList.push(ele);
+ });
+ }
+
+ function _toSelectList(arr){
+ var tempList = [];
+ angular.forEach(arr, function(ele){
+ tempList.push({'title': ele});
+ });
+ return tempList;
+ }
+
+ function goTest() {
+ $state.go("select.selectTestCase");
+ }
+
+ function goLogin() {
+ $state.go("login");
+ }
+ }]);
diff --git a/reporting/pages/app/scripts/factory/table.factory.js b/reporting/pages/app/scripts/factory/table.factory.js
index e715c5c..a2c5c76 100644
--- a/reporting/pages/app/scripts/factory/table.factory.js
+++ b/reporting/pages/app/scripts/factory/table.factory.js
@@ -6,7 +6,7 @@
angular.module('opnfvApp')
.factory('TableFactory', function($resource, $rootScope, $http) {
- var BASE_URL = 'http://testresults.opnfv.org/reporting2';
+ var BASE_URL = ' http://testresults.opnfv.org/testing';
$.ajax({
url: 'config.json',
async: false,
@@ -15,11 +15,19 @@ angular.module('opnfvApp')
BASE_URL = response.url;
},
error: function (response){
- alert('fail to get api url, using default: http://testresults.opnfv.org/reporting2')
+ alert('fail to get api url, using default: http://testresults.opnfv.org/testing')
}
});
return {
+ getScenarioResult: function() {
+ return $resource(BASE_URL + '/scenarios/results', {'scenario': '@scenario', 'version': '@version', 'installer': '@installer', 'iteration': '@iteration'}, {
+ 'get': {
+ method: 'GET',
+
+ }
+ });
+ },
getFilter: function() {
return $resource(BASE_URL + '/landing-page/filters', {}, {
'get': {
diff --git a/reporting/pages/app/views/gating.html b/reporting/pages/app/views/gating.html
new file mode 100644
index 0000000..0215c87
--- /dev/null
+++ b/reporting/pages/app/views/gating.html
@@ -0,0 +1,68 @@
+<section class="container-tablesize">
+ <div class="row border-bottom white-bg dashboard-header">
+ <div class="row">
+
+ <div class="ibox float-e-margins">
+ <div class="ibox-title">
+ <h5>OPNFV Release Gating Reporting </h5>
+ </div>
+
+ <div class="ibox-content row">
+ <div class="col-md-2" style="margin-top:5px;margin-right: 5px;">
+ <selectize options="scenarioList" ng-model="selectScenario" config="ScenarioConfig"></selectize>
+ </div>
+ <div class="col-md-2" style="margin-top:5px;margin-right: 5px;">
+ <selectize options="versionList" ng-model="selectVersion" config="VersionConfig"></selectize>
+ </div>
+
+ <div class="col-md-2" style="margin-top:5px;margin-right: 5px;">
+ <selectize options="installerList" ng-model="selectInstaller" config="InstallerConfig"></selectize>
+
+ </div>
+
+ <div class="col-md-2" style="margin-top:5px;margin-right: 5px;">
+ <selectize options="iterationList" ng-model="selectIteration" config="IterationConfig"></selectize>
+ </div>
+ </div>
+
+ <div class="table-responsive">
+ <table class="table table-bordered" id="table">
+ <thead class="thead">
+ <tr>
+ <th>Scenario</th>
+ <th>Date</th>
+ <th>ID</th>
+ <th>Version</th>
+ <th>Installer</th>
+ <th>Deployment</th>
+ <th>Functest</th>
+ <th>Yardstick</th>
+ </tr>
+ </thead>
+ <tbody class="tbody" ng-show="selectScenario == 'all' || scenario == selectScenario" ng-repeat="(scenario,value) in scenarios">
+ <tr ng-repeat="record in value">
+ <td ng-if="$index == 0">{{ scenario }}</td>
+ <td ng-if="$index != 0"></td>
+ <td>{{ record.date }}</td>
+ <td>{{ record.id }}</td>
+ <td>{{ record.version }}</td>
+ <td>{{ record.installer }}</td>
+ <td>{{ record.projects.deployment.gating }}</td>
+ <td>{{ record.projects.functest.gating }}</td>
+ <td>{{ record.projects.yardstick.gating }}</td>
+ </tr>
+ </tbody>
+ </table>
+
+ </div>
+
+ </div>
+ </div>
+ </div>
+
+</section>
+<style>
+.selectize-input {
+ width: 200px !important;
+}
+</style>
diff --git a/reporting/reporting/bottlenecks/reporting-status.py b/reporting/reporting/bottlenecks/reporting-status.py
index 225227a..8966d06 100644
--- a/reporting/reporting/bottlenecks/reporting-status.py
+++ b/reporting/reporting/bottlenecks/reporting-status.py
@@ -37,14 +37,10 @@ for version in VERSIONS:
# For all the installers
for installer in INSTALLERS:
# get scenarios results data
- if version != 'master':
- new_version = "stable/{}".format(version)
- else:
- new_version = version
scenario_results = rp_utils.getScenarios("bottlenecks",
"posca_factor_ping",
installer,
- new_version)
+ version)
LOGGER.info("scenario_results: %s", scenario_results)
scenario_stats = rp_utils.getScenarioStats(scenario_results)
diff --git a/reporting/reporting/functest/reporting-status.py b/reporting/reporting/functest/reporting-status.py
index 592f929..e36aede 100755
--- a/reporting/reporting/functest/reporting-status.py
+++ b/reporting/reporting/functest/reporting-status.py
@@ -25,8 +25,6 @@ Functest reporting status
LOGGER = rp_utils.getLogger("Functest-Status")
# Initialization
-testValid = []
-otherTestCases = []
reportingDate = datetime.datetime.now().strftime("%Y-%m-%d %H:%M")
# init just connection_check to get the list of scenarios
@@ -43,8 +41,7 @@ blacklist = rp_utils.get_config('functest.blacklist')
log_level = rp_utils.get_config('general.log.log_level')
exclude_noha = rp_utils.get_config('functest.exclude_noha')
exclude_virtual = rp_utils.get_config('functest.exclude_virtual')
-
-functest_yaml_config = rp_utils.getFunctestConfig()
+tiers_for_scoring = {'healthcheck', 'smoke', 'vnf', 'features'}
LOGGER.info("*******************************************")
LOGGER.info("* *")
@@ -57,38 +54,36 @@ LOGGER.info("* NOHA scenarios excluded: %s *", exclude_noha)
LOGGER.info("* *")
LOGGER.info("*******************************************")
-# Retrieve test cases of Tier 1 (smoke)
-config_tiers = functest_yaml_config.get("tiers")
+# For all the versions
+for version in versions:
+ testValid = []
+ # Retrieve test cases of Tier 1 (smoke)
+ version_config = ""
+ if (version != "master" and version != "latest"):
+ version_config = "?h=stable/" + version
+ functest_yaml_config = rp_utils.getFunctestConfig(version_config)
+ config_tiers = functest_yaml_config.get("tiers")
+
+ # we consider Tier 0 (Healthcheck), Tier 1 (smoke),2 (features)
+ # to validate scenarios
+ # Tier > 2 are not used to validate scenarios but we display
+ # the results anyway
+ # tricky thing for the API as some tests are Functest tests
+ # other tests are declared directly in the feature projects
+ for tier in config_tiers:
-# we consider Tier 0 (Healthcheck), Tier 1 (smoke),2 (features)
-# to validate scenarios
-# Tier > 2 are not used to validate scenarios but we display the results anyway
-# tricky thing for the API as some tests are Functest tests
-# other tests are declared directly in the feature projects
-for tier in config_tiers:
- if tier['order'] >= 0 and tier['order'] < 2:
for case in tier['testcases']:
+ try:
+ dependencies = case['dependencies']
+ except KeyError:
+ dependencies = ""
if case['case_name'] not in blacklist:
testValid.append(tc.TestCase(case['case_name'],
"functest",
- case['dependencies']))
- elif tier['order'] == 2:
- for case in tier['testcases']:
- if case['case_name'] not in blacklist:
- otherTestCases.append(tc.TestCase(case['case_name'],
- case['case_name'],
- case['dependencies']))
- elif tier['order'] > 2:
- for case in tier['testcases']:
- if case['case_name'] not in blacklist:
- otherTestCases.append(tc.TestCase(case['case_name'],
- "functest",
- case['dependencies']))
+ dependencies,
+ tier=tier['name']))
+ LOGGER.debug("Functest reporting start")
-LOGGER.debug("Functest reporting start")
-
-# For all the versions
-for version in versions:
# For all the installers
scenario_directory = "./display/" + version + "/functest/"
scenario_file_name = scenario_directory + "scenario_history.txt"
@@ -155,10 +150,8 @@ for version in versions:
# Check if test case is runnable / installer, scenario
# for the test case used for Scenario validation
try:
- # 1) Manage the test cases for the scenario validation
- # concretely Tiers 0-3
for test_case in testValid:
- test_case.checkRunnable(installer, s,
+ test_case.checkRunnable(installer, s, architecture,
test_case.getConstraints())
LOGGER.debug("testcase %s (%s) is %s",
test_case.getDisplayName(),
@@ -169,7 +162,8 @@ for version in versions:
name = test_case.getName()
displayName = test_case.getDisplayName()
project = test_case.getProject()
- nb_test_runnable_for_this_scenario += 1
+ if test_case.getTier() in tiers_for_scoring:
+ nb_test_runnable_for_this_scenario += 1
LOGGER.info(" Searching results for case %s ",
displayName)
if "fuel" in installer:
@@ -185,53 +179,18 @@ for version in versions:
LOGGER.info(" >>>> Test score = " + str(result))
test_case.setCriteria(result)
test_case.setIsRunnable(True)
- testCases2BeDisplayed.append(tc.TestCase(name,
- project,
- "",
- result,
- True,
- 1))
- scenario_score = scenario_score + result
-
- # 2) Manage the test cases for the scenario qualification
- # concretely Tiers > 3
- for test_case in otherTestCases:
- test_case.checkRunnable(installer, s,
- test_case.getConstraints())
- LOGGER.debug("testcase %s (%s) is %s",
- test_case.getDisplayName(),
- test_case.getName(),
- test_case.isRunnable)
- time.sleep(1)
- if test_case.isRunnable:
- name = test_case.getName()
- displayName = test_case.getDisplayName()
- project = test_case.getProject()
- LOGGER.info(" Searching results for case %s ",
- displayName)
- if "fuel" in installer:
- result = rp_utils.getCaseScoreFromBuildTag(
- name,
- s_result)
- else:
- result = rp_utils.getCaseScore(name, installer,
- s, version)
- # at least 1 result for the test
- if result > -1:
- test_case.setCriteria(result)
- test_case.setIsRunnable(True)
- testCases2BeDisplayed.append(tc.TestCase(
- name,
- project,
- "",
- result,
- True,
- 4))
- else:
- LOGGER.debug("No results found")
-
- items[s] = testCases2BeDisplayed
- except Exception: # pylint: disable=broad-except
+ testCases2BeDisplayed.append(
+ tc.TestCase(name,
+ project,
+ "",
+ result,
+ True,
+ tier=test_case.getTier()))
+ if test_case.getTier() in tiers_for_scoring:
+ scenario_score = scenario_score + result
+
+ items[s] = testCases2BeDisplayed
+ except KeyError: # pylint: disable=broad-except
LOGGER.error("Error installer %s, version %s, scenario %s",
installer, version, s)
LOGGER.error("No data available: %s", sys.exc_info()[0])
@@ -259,6 +218,12 @@ for version in versions:
else:
k_score = 2
+ # TODO for the scoring we should consider 3 tiers
+ # - Healthcheck
+ # - Smoke
+ # - Vnf
+ # components
+
scenario_criteria = nb_test_runnable_for_this_scenario*k_score
# score for reporting
diff --git a/reporting/reporting/functest/reporting-tempest.py b/reporting/reporting/functest/reporting-tempest.py
index d78d9a1..b82f96c 100755
--- a/reporting/reporting/functest/reporting-tempest.py
+++ b/reporting/reporting/functest/reporting-tempest.py
@@ -83,8 +83,16 @@ for version in rp_utils.get_config('general.versions'):
# retrieve results
# ****************
- nb_tests_run = result['details']['tests']
- nb_tests_failed = result['details']['failures']
+ try:
+ nb_tests_run = result['details']['success_number']
+ nb_tests_failed = result['details']['failures_number']
+ except KeyError:
+ try:
+ nb_tests_run = result['details']['tests']
+ nb_tests_failed = result['details']['failures']
+ except KeyError:
+ logger.error("Impossible to retrieve results")
+
logger.debug("nb_tests_run= %s", nb_tests_run)
logger.debug("nb_tests_failed= %s", nb_tests_failed)
@@ -140,12 +148,14 @@ for version in rp_utils.get_config('general.versions'):
# Error management
# ****************
try:
- errors = result['details']['errors']
- logger.info("errors: %s", errors)
- result['errors'] = errors
- except Exception: # pylint: disable=broad-except
- logger.error("Error field not present (Brahamputra runs?)")
-
+ errors = result['details']['failures']
+ except KeyError:
+ try:
+ errors = result['details']['errors']
+ except KeyError:
+ logger.error("Error field not present (old runs?)")
+ logger.info("errors: %s", errors)
+ result['errors'] = errors
templateLoader = jinja2.FileSystemLoader(".")
templateEnv = jinja2.Environment(loader=templateLoader,
autoescape=True)
diff --git a/reporting/reporting/functest/reporting-vims.py b/reporting/reporting/functest/reporting-vims.py
index 3b25e91..bc9308c 100755
--- a/reporting/reporting/functest/reporting-vims.py
+++ b/reporting/reporting/functest/reporting-vims.py
@@ -120,7 +120,7 @@ for version in VERSIONS:
LOGGER.debug("vIMS deployment: %ss", res_vnf)
LOGGER.debug("VNF testing: %ss", res_test_vnf)
LOGGER.debug("VNF testing results: %s", format_result)
- except Exception as err: # pylint: disable=broad-except
+ except KeyError as err: # pylint: disable=broad-except
LOGGER.error("Uncomplete data %s", err)
LOGGER.debug("----------------------------------------")
diff --git a/reporting/reporting/functest/template/index-status-tmpl.html b/reporting/reporting/functest/template/index-status-tmpl.html
index 50fc648..48b5a2d 100644
--- a/reporting/reporting/functest/template/index-status-tmpl.html
+++ b/reporting/reporting/functest/template/index-status-tmpl.html
@@ -144,33 +144,32 @@ $(document).ready(function (){
<span class="panel-header-item">
</span>
</div>
+ {% for tier in ['healthcheck', 'smoke', 'vnf', 'features'] -%}
<table class="table">
<tr>
+ <h2>{{tier}}</h2>
{% for test in items[scenario] -%}
- <th>
- {% if test.getCriteria() > -1 -%}
- {{test.getDisplayName() }}
+ {% if test.getCriteria() > -1 and test.getTier() == tier -%}
+ <th>{{test.getDisplayName() }}</th>
{%- endif %}
- {% if test.getTier() > 3 -%}
- *
- {%- endif %}
- </th>
- {%- endfor %}
+ {%- endfor %}
</tr>
<tr class="tr-weather-weather">
- {% for test in items[scenario] -%}
- {% if test.getCriteria() > 2 -%}
+ {% for test in items[scenario] -%}
+ {% if test.getCriteria() > 2 and test.getTier() == tier -%}
<td><img src="../../img/weather-clear.png"></td>
- {%- elif test.getCriteria() > 1 -%}
+ {%- elif test.getCriteria() > 1 and test.getTier() == tier -%}
<td><img src="../../img/weather-few-clouds.png"></td>
- {%- elif test.getCriteria() > 0 -%}
+ {%- elif test.getCriteria() > 0 and test.getTier() == tier -%}
<td><img src="../../img/weather-overcast.png"></td>
- {%- elif test.getCriteria() > -1 -%}
+ {%- elif test.getCriteria() > -1 and test.getTier() == tier -%}
<td><img src="../../img/weather-storm.png"></td>
{%- endif %}
{%- endfor %}
</tr>
</table>
+ <br><hr>
+ {%- endfor %}
</div>
</div>
{%- endfor %}
diff --git a/reporting/reporting/functest/testCase.py b/reporting/reporting/functest/testCase.py
index a182dd4..fba3216 100644
--- a/reporting/reporting/functest/testCase.py
+++ b/reporting/reporting/functest/testCase.py
@@ -26,7 +26,9 @@ class TestCase(object):
'onos': 'ONOS',
'ocl': 'OCL',
'tempest_smoke_serial': 'Tempest (smoke)',
+ 'tempest_smoke': 'Tempest (smoke)',
'tempest_full_parallel': 'Tempest (full)',
+ 'tempest_full': 'Tempest (full)',
'tempest_defcore': 'Tempest (Defcore)',
'refstack_defcore': 'Refstack',
'rally_sanity': 'Rally (smoke)',
@@ -43,20 +45,45 @@ class TestCase(object):
'functest-odl-sfc': 'SFC',
'onos_sfc': 'SFC',
'parser-basics': 'Parser',
- 'connection_check': 'Health (connection)',
- 'api_check': 'Health (api)',
+ 'connection_check': 'connectivity',
+ 'api_check': 'api',
'snaps_smoke': 'SNAPS',
- 'snaps_health_check': 'Health (dhcp)',
+ 'snaps_health_check': 'dhcp',
'gluon_vping': 'Netready',
'fds': 'FDS',
'cloudify_ims': 'vIMS (Cloudify)',
+ 'cloudify': 'Cloudify',
'orchestra_openims': 'OpenIMS (OpenBaton)',
'orchestra_clearwaterims': 'vIMS (OpenBaton)',
'opera_ims': 'vIMS (Open-O)',
'vyos_vrouter': 'vyos (Cloudify)',
'barometercollectd': 'Barometer',
'odl_netvirt': 'Netvirt',
- 'security_scan': 'Security'}
+ 'security_scan': 'Security',
+ 'patrole': 'Patrole',
+ 'tenantnetwork1': 'tenant network 1',
+ 'tenantnetwork2': 'tenant network 2',
+ 'vmready1': 'vm ready 1',
+ 'vmready2': 'vm ready 2',
+ 'singlevm1': 'single vm 1',
+ 'singlevm2': 'single vm 2',
+ 'cinder_test': 'cinder tests',
+ 'barbican': 'barbican',
+ 'vmtp': 'vmtp',
+ 'juju_epc': 'vEPC (Juju)',
+ 'shaker': 'shaker',
+ 'neutron_trunk': 'Neutron trunk',
+ 'tempest_scenario': 'tempest_scenario',
+ 'networking-bgpvpn': 'networking-bgpvpn',
+ 'networking-sfc': 'networking-sfc',
+ 'tempest_full': 'Tempest (full)',
+ 'cloudify': 'cloudify',
+ 'heat_ims': 'vIMS (Heat)',
+ 'vmtp': 'vmtp',
+ 'tempest_smoke': 'Tempest (smoke)',
+ 'neutron-tempest-plugin-api': 'Neutron API',
+ 'vgpu': 'vgpu',
+ 'stor4nfv_os': 'stor4nfv_os'}
try:
self.displayName = display_name_matrix[self.name]
except:
@@ -68,22 +95,22 @@ class TestCase(object):
def getProject(self):
return self.project
- def getConstraints(self):
- return self.constraints
-
def getCriteria(self):
return self.criteria
def getTier(self):
return self.tier
+ def getConstraints(self):
+ return self.constraints
+
def setCriteria(self, criteria):
self.criteria = criteria
def setIsRunnable(self, isRunnable):
self.isRunnable = isRunnable
- def checkRunnable(self, installer, scenario, config):
+ def checkRunnable(self, installer, scenario, arch, config):
# Re-use Functest declaration
# Retrieve Functest configuration file functest_config.yaml
is_runnable = True
@@ -98,27 +125,36 @@ class TestCase(object):
# Retrieve test constraints
# Retrieve test execution param
- test_execution_context = {"installer": installer,
- "scenario": scenario}
+ test_execution_context = {"INSTALLER_TYPE": installer,
+ "DEPLOY_SCENARIO": scenario,
+ "POD_ARCH": arch}
+
+ # 3 types of constraints
+ # INSTALLER_TYPE
+ # DEPLOY_SCENARIO
+ # POD_ARCH
# By default we assume that all the tests are always runnable...
# if test_env not empty => dependencies to be checked
- if config_test is not None and len(config_test) > 0:
- # possible criteria = ["installer", "scenario"]
- # consider test criteria from config file
- # compare towards CI env through CI en variable
- for criteria in config_test:
- if re.search(config_test[criteria],
- test_execution_context[criteria]) is None:
- # print "Test "+ test + " cannot be run on the environment"
- is_runnable = False
+ try:
+ if config_test is not None and len(config_test) > 0:
+ # possible criteria = ["installer", "scenario"]
+ # consider test criteria from config file
+ # compare towards CI env through CI en variable
+ for criterias in config_test:
+ for criteria_key, criteria_value in criterias.iteritems():
+ if re.search(
+ criteria_value,
+ test_execution_context[criteria_key]) is None:
+ is_runnable = False
+ except AttributeError:
+ is_runnable = False
# print is_runnable
self.isRunnable = is_runnable
def toString(self):
testcase = ("Name=" + self.name + ";Criteria=" +
str(self.criteria) + ";Project=" + self.project +
- ";Constraints=" + str(self.constraints) +
";IsRunnable" + str(self.isRunnable))
return testcase
diff --git a/reporting/reporting/reporting.yaml b/reporting/reporting/reporting.yaml
index 8123d01..6a59a44 100644
--- a/reporting/reporting/reporting.yaml
+++ b/reporting/reporting/reporting.yaml
@@ -9,7 +9,7 @@ general:
versions:
- master
- - euphrates
+ - gambia
log:
log_file: reporting.log
@@ -36,9 +36,11 @@ testapi:
functest:
blacklist:
- odl_netvirt
- - juju_epc
- tempest_full_parallel
+ - tempest_full
- rally_full
+ - heat_ims
+ - tempest_scenario
max_scenario_criteria: 50
test_conf: https://git.opnfv.org/cgit/functest/plain/functest/ci/testcases.yaml
log_level: ERROR
diff --git a/reporting/reporting/vsperf/reporting-status.py b/reporting/reporting/vsperf/reporting-status.py
index b307ef0..377c315 100644
--- a/reporting/reporting/vsperf/reporting-status.py
+++ b/reporting/reporting/vsperf/reporting-status.py
@@ -127,7 +127,7 @@ def main():
period=50)
version_data = _get_version_data(data['vsperf'])
- for version in {'master', 'danube', 'euphrates'}:
+ for version in {'master', 'fraser', 'gambia'}:
_generate_reporting(version, version_data.get(version, []))
LOG.info("End")
diff --git a/reporting/reporting/yardstick/reporting-status.py b/reporting/reporting/yardstick/reporting-status.py
index 10cacf0..a6e3cdf 100644
--- a/reporting/reporting/yardstick/reporting-status.py
+++ b/reporting/reporting/yardstick/reporting-status.py
@@ -140,8 +140,7 @@ def generate_reporting_page(version, installer, archi, scenarios, period):
percent)
LOG.info("--------------------------")
- if scenario_data:
- generate_page(scenario_data, installer, period, version, archi)
+ generate_page(scenario_data, installer, period, version, archi)
def main():
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..2b20d6b 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,64 @@ 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;
+}
+
+#toast {
+ visibility: hidden;
+ min-width: 250px;
+ margin-left: -125px;
+ color: #fff;
+ text-align: center;
+ border-radius: 10px;
+ padding: 16px;
+ position: fixed;
+ z-index: 9999;
+ left: 50%;
+ bottom: 30px;
+}
+
+#toast.error{
+ background-color: #B03838;
+}
+
+#toast.success{
+ background-color: #1A911E;
+}
+
+#toast.show {
+ visibility: visible;
+
+ -webkit-animation: fadein 0.5s, fadeout 0.5s 2.5s;
+ animation: fadein 0.5s, fadeout 0.5s 2.5s;
+}
+
+@-webkit-keyframes fadein {
+ from {bottom: 0; opacity: 0;}
+ to {bottom: 30px; opacity: 1;}
+}
+
+@keyframes fadein {
+ from {bottom: 0; opacity: 0;}
+ to {bottom: 30px; opacity: 1;}
+}
+
+@-webkit-keyframes fadeout {
+ from {bottom: 30px; opacity: 1;}
+ to {bottom: 0; opacity: 0;}
+}
+
+@keyframes fadeout {
+ from {bottom: 30px; opacity: 1;}
+ to {bottom: 0; opacity: 0;}
+} \ 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..59389b0
--- /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-2" ng-class="{\'hidden\' : key==\'\' && key!=\'0\'}" ng-click="toggleExpanded()">{{key}}</span> <span class="leaf-value col-md-10" 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/docker/Dockerfile b/testapi/docker/Dockerfile
index bbf12fc..03b15e8 100644
--- a/testapi/docker/Dockerfile
+++ b/testapi/docker/Dockerfile
@@ -23,30 +23,31 @@
# http://www.apache.org/licenses/LICENSE-2.0
#
-FROM ubuntu:14.04
+FROM ubuntu:18.04
MAINTAINER SerenaFeng <feng.xiaowei@zte.com.cn>
LABEL version="v1" description="OPNFV TestAPI Docker container"
-ENV HOME /home
+ARG user=ubuntu
+ARG group=ubuntu
-# Packaged dependencies
RUN apt-get update && apt-get install -y \
-curl \
-git \
-gcc \
-wget \
-python-dev \
-python-pip \
-crudini \
---no-install-recommends
-
-RUN pip install --upgrade pip requests
-
-RUN git config --global http.sslVerify false
-RUN git clone https://gerrit.opnfv.org/gerrit/releng-testresults /home/releng-testresults
-
-WORKDIR /home/releng-testresults/testapi
-RUN pip install -r requirements.txt
-
-RUN python setup.py install
+ curl git gcc wget python-dev python-pip python-wheel python-setuptools \
+ crudini libxslt-dev zlib1g-dev --no-install-recommends && \
+ groupadd -r $group && useradd -ms /bin/bash $user -g $group && \
+ git clone https://gerrit.opnfv.org/gerrit/releng-testresults \
+ /home/ubuntu/releng-testresults && \
+ pip install -r /home/ubuntu/releng-testresults/testapi/requirements.txt \
+ -c /home/ubuntu/releng-testresults/testapi/upper-constraints.txt \
+ -c https://raw.githubusercontent.com/openstack/requirements/stable/ussuri/upper-constraints.txt && \
+ sed -i '152,152s/)/,\ verify=False)/g' \
+ /usr/local/lib/python2.7/dist-packages/cas.py && \
+ cd /home/ubuntu/releng-testresults/testapi/ && python setup.py install && \
+ for i in /home/ubuntu/releng-testresults /etc/opnfv_testapi /usr/local/share/opnfv_testapi; do \
+ mkdir -p $i && chown -R $user:$group $i && \
+ find $i -type d |xargs chmod 777 && \
+ find $i -type f |xargs chmod 666 ; done && \
+ apt-get remove --purge -y python-dev libxslt-dev zlib1g-dev && \
+ apt-get autoremove --purge -y && apt-get clean && rm -rf /var/lib/apt/lists/*
+WORKDIR /home/ubuntu/releng-testresults/testapi
+USER ubuntu
CMD ["bash", "docker/start-server.sh"]
diff --git a/testapi/docker/prepare-env.sh b/testapi/docker/prepare-env.sh
index 9086e77..3b061d2 100755
--- a/testapi/docker/prepare-env.sh
+++ b/testapi/docker/prepare-env.sh
@@ -2,18 +2,20 @@
FILE=/etc/opnfv_testapi/config.ini
-if [ "$mongodb_url" != "" ]; then
- sudo crudini --set --existing $FILE mongo url $mongodb_url
-fi
+[[ "${mongodb_url}" == "" ]] && mongodb_url=mongodb://mongo:27017/
+[[ "${base_url}" == "" ]] && base_url=http://localhost:8000
+[[ ! "${auth}" =~ [f|F]alse ]] && auth=true
-if [ "$base_url" != "" ]; then
- sudo crudini --set --existing $FILE api url $base_url/api/v1
- sudo crudini --set --existing $FILE ui url $base_url
- sudo cat > /usr/local/share/opnfv_testapi/testapi-ui/config.json << EOF
+auth_server=`echo ${auth:0:1} | tr '[:lower:]' '[:upper:]'``echo ${auth:1} | tr '[:upper:]' '[:lower:]'`
+auth_web=`echo ${auth} | tr '[:upper:]' '[:lower:]'`
+crudini --set --existing ${FILE} mongo url ${mongodb_url}
+crudini --set --existing ${FILE} api url ${base_url}/api/v1
+crudini --set --existing ${FILE} ui url ${base_url}
+crudini --set --existing ${FILE} api authenticate ${auth_server}
+
+cat > /usr/local/share/opnfv_testapi/testapi-ui/config.json << EOF
{
- "testapiApiUrl": "$base_url/api/v1",
- "authenticate": true
+ "testapiApiUrl": "${base_url}/api/v1",
+ "authenticate": ${auth_web}
}
EOF
-
-fi
diff --git a/testapi/docs/developer/devguide/images/CAS-sequence.jpg b/testapi/docs/developer/devguide/images/CAS-sequence.jpg
new file mode 100644
index 0000000..a624871
--- /dev/null
+++ b/testapi/docs/developer/devguide/images/CAS-sequence.jpg
Binary files differ
diff --git a/testapi/docs/developer/devguide/testapi-client-import.rst b/testapi/docs/developer/devguide/testapi-client-import.rst
new file mode 100644
index 0000000..c6d7311
--- /dev/null
+++ b/testapi/docs/developer/devguide/testapi-client-import.rst
@@ -0,0 +1,974 @@
+.. This work is licensed under a Creative Commons Attribution 4.0 International License.
+.. http://creativecommons.org/licenses/by/4.0
+.. (c) 2017 ZTE Corp.
+
+=====================
+TestAPI client import
+=====================
+
+**Python module to communicate with the TestAPI Server**
+
+This project aims to provide a python module which can
+communicate with the TestAPI Server. The user can use this client
+to fetch/post/modify the resources on the TestAPI Server.
+
+Usage
+-----
+
+Pod
+^^^
+
+GET
+"""
+
+Get a list of all the declared pods from the TestAPI server.
+
+.. code-block:: shell
+
+ from testapiclient.client import pods
+
+ pod_client = pods.PodsClient()
+ pod_client.get()
+
+The user can filter the results by the name attribute. Backend will
+use a regular expression to find the list of pods which are
+related to given name.
+
+.. code-block:: shell
+
+ from testapiclient.client import pods
+
+ pod_client = pods.PodsClient()
+ pod_client.get(name='pod1')
+
+.. NOTE::
+ Response format: [{"_id": "", "creator": "", "role": "", "name": "",
+ "details": "", "mode": "", "creation_date": ""}]
+
+
+GET ONE
+"""""""
+
+Get a specific pod by its name.
+
+.. code-block:: shell
+
+ from testapiclient.client import pods
+
+ pod_client = pods.PodsClient()
+ pod_client.get_one('name')
+
+.. NOTE::
+ Response format: {"_id": "", "creator": "", "role": "", "name": "",
+ "details": "", "mode": "", "creation_date": ""}
+
+CREATE
+""""""
+This method used to create a project on the server.
+The user should provide the user parameter and the password
+parameter while initiating the PodsClient.
+
+Input for the function :
+
+ * pod-json : Json object of the project
+
+.. NOTE::
+ pod-json-schema - '{"role": "", "name": "", "details": "", "mode": ""}'
+
+ * role should be either "community-ci" or "production-ci"
+ * mode should be either "metal" or "virtual"
+
+.. code-block:: shell
+
+ from testapiclient.client import pods
+
+ pod_client = pods.PodsClient(user='test', password='pass')
+ pod_client.create({'name': 'test-api', 'mode':'metal',
+ 'role':'community_ci', 'details':''})
+
+
+Project
+^^^^^^^
+
+GET
+"""
+
+Get a list of all the declared projects from the TestAPI server.
+
+.. code-block:: shell
+
+ from testapiclient.client import projects
+
+ project_client = projects.ProjectsClient()
+ project_client.get()
+
+User can filter the results by the name attribute. Backend will
+use a regular expression to find the list of projects which are
+related to given name.
+
+.. code-block:: shell
+
+ from testapiclient.client import projects
+
+ project_client = projects.ProjectsClient()
+ project_client.get(name='project1')
+
+.. NOTE::
+ Response format: [{"_id": "", "creator": "", "description": "",
+ "name": "", "creation_date": ""}]
+
+GET ONE
+"""""""
+
+Get a specific project by its name.
+
+.. code-block:: shell
+
+ from testapiclient.client import projects
+
+ project_client = projects.ProjectsClient()
+ project_client.get_one('name')
+
+.. NOTE::
+ Response format: {"_id": "", "creator": "", "description": "",
+ "name": "", "creation_date": ""}
+
+CREATE
+""""""
+
+This method used to create a project on the server.
+The user should provide the user parameter and the password
+parameter while initiating the ProjectsClient.
+
+Input for the function :
+
+ * project-json : Json object of the project
+
+.. NOTE::
+ project-json schema - '{"description": "", "name": ""}'
+
+.. code-block:: shell
+
+ from testapiclient.client import projects
+
+ project_client = projects.ProjectsClient(user='test', password='pass')
+ project_client.create({'name': 'functest', 'description':'sample text'}
+
+UPDATE
+""""""
+
+This method used to update an existing project on the server.
+The user should provide the user parameter and the password
+parameter while initiating the ProjectsClient.
+
+Input for the function :
+
+ * project-name: name of the project which user want to update.
+ * project-json: Json object of the project
+
+.. NOTE::
+ project-json schema - '{"description": "", "name": ""}'
+
+.. code-block:: shell
+
+ from testapiclient.client import projects
+
+ project_client = projects.ProjectsClient(user='test', password='pass')
+ project_client.update('functest', {'name': 'functest',
+ 'description':'updated text'})
+
+DELETE
+""""""
+
+This method used to delete an existing project on the server.
+The user should provide the user parameter and the password
+parameter while initiating the ProjectsClient.
+
+Input for the function :
+
+ * project-name: name of the project which user want to delete.
+
+.. code-block:: shell
+
+ from testapiclient.client import projects
+
+ project_client = projects.ProjectsClient(user='test', password='pass')
+ project_client.delete('functest')
+
+
+Testcase
+^^^^^^^^
+
+GET
+"""
+
+Get a list of all the declared testcases under a project
+from the TestAPI server.
+
+Input for the function :
+
+ * project_name : Name of the project
+
+.. code-block:: shell
+
+ from testapiclient.client import testcases
+
+ testcase_client = testcases.TestcasesClient()
+ testcase_client.get(project_name='functest')
+
+
+.. NOTE::
+ Response format: [{ "project_name": "functest", "run": "",
+ "description": "", "tags": "", "creation_date": "",
+ "dependencies": "", "tier": "", "trust": "", "blocking": "",
+ "name": "", "ci_loop": "", "url": "", "version": "",
+ "criteria": "", "domains": "", "_id": "", "catalog_description": ""}]
+
+GET ONE
+"""""""
+
+Get a specific testcase by its name and project name.
+
+.. code-block:: shell
+
+ from testapiclient.client import testcases
+
+ testcase_client = testcases.TestcasesClient()
+ testcase_client.get_one(project_name='functest', case_name='name')
+
+.. NOTE::
+ Response format: { "project_name": "functest", "run": "",
+ "description": "", "tags": "", "creation_date": "",
+ "dependencies": "", "tier": "", "trust": "", "blocking": "",
+ "name": "", "ci_loop": "", "url": "", "version": "",
+ "criteria": "", "domains": "", "_id": "", "catalog_description": ""}
+
+CREATE
+""""""
+
+This method used to create a testcase on the server.
+The user should provide the user parameter and the password
+parameter while initiating the TestcasesClient.
+
+Input for the function :
+ * project_name : Project name
+ * testcase_json : Json object of the testcase
+
+.. NOTE::
+ testcase_json schema - '{ "run": "", "description": "", "tags": "",
+ "dependencies": "", "tier": "", "trust": "", "blocking": "",
+ "name": "", "ci_loop": "", "url": "", "version": "",
+ "criteria": "", "domains": "", "catalog_description": ""}'
+
+.. code-block:: shell
+
+ from testapiclient.client import testcases
+
+ testcase_client = testcases.TestcasesClient(user='test', password='pass')
+ testcase_client.create(project_name, testcase_json)
+
+UPDATE
+""""""
+
+This method used to update an existing testcase on the server.
+The user should provide the user parameter and the password
+parameter while initiating the TestcasesClient.
+
+Input for the function :
+ * project_name : Project name
+ * testcase_name: name of the testcase which user want to update.
+ * testcase_json: Json object of the testcase
+
+.. NOTE::
+ testcase-json schema - '{ "run": "", "description": "", "tags": "",
+ "dependencies": "", "tier": "", "trust": "", "blocking": "",
+ "name": "", "ci_loop": "", "url": "", "version": "",
+ "criteria": "", "domains": "", "catalog_description": ""}'
+
+.. code-block:: shell
+
+ from testapiclient.client import testcases
+
+ testcase_client = testcases.TestcasesClient(user='test', password='pass')
+ testcase_client.update(project_name, testcase_name, testcase_json)
+
+DELETE
+""""""
+
+This method used to delete an existing testcase on the server.
+The user should provide the user parameter and the password
+parameter while initiating the TestcasesClient.
+
+Input for the function :
+
+ * project_name: name of the project
+ * testcase_name: name of the testcase which user want to delete.
+
+.. code-block:: shell
+
+ from testapiclient.client import testcases
+
+ testcase_client = testcases.TestcasesClient(user='test', password='pass')
+ testcase_client.delete(project_name, testcase_name)
+
+
+Result
+^^^^^^^
+
+GET
+"""
+
+Get a list of all the declared results from the TestAPI server.
+
+.. code-block:: shell
+
+ from testapiclient.client import results
+
+ result_client = results.ResultsClient()
+ result_client.get()
+
+User can filter the results by using some attributes.
+
+.. NOTE::
+ List of search attributes.
+
+ * case : Search results using tesetcase
+ * build-tag : Search results using build tag
+ * from : Search results using from date
+ * last : Search results using last date
+ * scenario : Search results using scenario
+ * period : Search results using period
+ * project : Search results using project
+ * to : Search results using to
+ * version : Search results using version
+ * criteria : Search results using criteria
+ * installer : Search results using installer
+ * pod : Search results using pod
+ * page : Search results using page
+
+.. code-block:: shell
+
+ from testapiclient.client import results
+
+ result_client = results.ResultsClient()
+ result_client.get(pod='pod1', project='project1')
+
+
+.. NOTE::
+ Response format: [{ "project_name": "", "scenario": "",
+ "stop_date": "", "case_name": "", "build_tag": "",
+ "version": "", "pod_name": "", "criteria": "",
+ "installer": "", "start_date": "", "details": ""}]
+
+GET ONE
+"""""""
+
+Get a specific result by its id.
+
+.. code-block:: shell
+
+ from testapiclient.client import results
+
+ result_client = results.ResultsClient()
+ result_client.get_one(result_id)
+
+.. NOTE::
+ Response format: { "project_name": "", "scenario": "",
+ "stop_date": "", "case_name": "", "build_tag": "",
+ "version": "", "pod_name": "", "criteria": "",
+ "installer": "", "start_date": "", "details": ""}
+
+CREATE
+""""""
+
+This method used to create a result on the server.
+The user should provide a valid token to run this method.
+Read testapi-client.rst to more details.
+
+Input for the function :
+ * result_json : Json object of the result
+
+.. NOTE::
+ result_json schema - '{ "project_name": "", "scenario": "",
+ "stop_date": "", "case_name": "", "build_tag": "",
+ "version": "", "pod_name": "", "criteria": "",
+ "installer": "", "start_date": "", "details": ""}'
+
+.. code-block:: shell
+
+ from testapiclient.client import results
+
+ result_client = results.ResultsClient()
+ result_client.create(result_json)
+
+DeployResult
+^^^^^^^^^^^^
+
+GET
+"""
+
+Get a list of all the declared deploy results from the TestAPI server.
+
+.. code-block:: shell
+
+ from testapiclient.client import deploy_results
+
+ deploy_result_client = deploy_results.DeployResultsClient()
+ deploy_result_client.get()
+
+User can filter the deploy results by using some attributes.
+
+.. NOTE::
+ List of search attributes.
+
+ * job-name : Search results using job
+ * build_id : Search results using build id
+ * from : Search results using from date
+ * last : Search results using last date
+ * scenario : Search results using scenario
+ * period : Search results using period
+ * to : Search results using to
+ * version : Search results using version
+ * criteria : Search results using criteria
+ * installer : Search results using installer
+ * pod_name : Search results using pod
+ * page : Search results using page
+
+.. code-block:: shell
+
+ from testapiclient.client import deploy_results
+
+ deploy_result_client = deploy_results.DeployResultsClient()
+ deploy_result_client.get(scenario='scenario1', installer='installer1')
+
+
+.. NOTE::
+ Response format: [{"build_id": "", "upstream_build_id": "",
+ "scenario": "", "stop_date": "", "start_date": "",
+ "upstream_job_name": "", "version": "", "pod_name": "",
+ "criteria": "", "installer": "", "_id": "", "job_name": "",
+ "details": ""}]
+
+GET ONE
+"""""""
+
+Get a specific deploy result by its id.
+
+.. code-block:: shell
+
+ from testapiclient.client import deploy_results
+
+ deploy_result_client = deploy_results.DeployResultsClient()
+ deploy_result_client.get_one(deploy_result_id)
+
+.. NOTE::
+ Response format: {"build_id": "", "upstream_build_id": "",
+ "scenario": "", "stop_date": "", "start_date": "",
+ "upstream_job_name": "", "version": "", "pod_name": "",
+ "criteria": "", "installer": "", "_id": "", "job_name": "",
+ "details": ""}
+
+CREATE
+""""""
+
+This method used to create a deploy_result on the server.
+The user should provide a valid token to run this method.
+Read testapi-client.rst to more details.
+
+Input for the function :
+ * deploy_result_json : Json object of the deploy_result
+
+.. NOTE::
+ deploy_result_json schema - '{"build_id": "", "upstream_build_id": "",
+ "scenario": "", "stop_date": "", "start_date": "",
+ "upstream_job_name": "", "version": "", "pod_name": "",
+ "criteria": "", "installer": "", "job_name": "",
+ "details": ""}'
+
+.. code-block:: shell
+
+ from testapiclient.client import deploy_results
+
+ deploy_result_client = deploy_results.DeployResultsClient()
+ deploy_result_client.create(deploy_result_json)
+
+Scenario
+^^^^^^^^
+
+GET
+"""
+
+Get a list of all the declared scenarios from the TestAPI server.
+
+.. code-block:: shell
+
+ from testapiclient.client import scenarios
+
+ scenario_client = scenarios.ScenariosClient()
+ scenario_client.get()
+
+User can filter the scenarios by using some attributes.
+
+.. NOTE::
+ List of search attributes.
+
+ * project : Search scenarios using project
+ * installer : Search scenarios using project
+ * version : Search scenarios using project
+ * name: Search scenarios using project
+
+.. code-block:: shell
+
+ from testapiclient.client import scenarios
+
+ scenario_client = scenarios.ScenariosClient()
+ scenario_client.get(name='scenario1')
+
+.. NOTE::
+ Response format: [{ "installers": [], "_id": "", "creation_date": "",
+ "name": "", "creator": ""}]
+
+GET ONE
+"""""""
+
+Get a specific scenario by its name.
+
+.. code-block:: shell
+
+ from testapiclient.client import scenarios
+
+ scenario_client = scenarios.ScenariosClient()
+ scenario_client.get_one('name')
+
+.. NOTE::
+ Response format: { "installers": [], "_id": "", "creation_date": "",
+ "name": "", "creator": ""}
+
+CREATE
+""""""
+
+This method used to create a scenario on the server.
+The user should provide the user parameter and the password
+parameter while initiating the ScenariosClient.
+
+Input for the function :
+
+ * scenario-json : Json object of the scenario
+
+.. NOTE::
+ scenario_json schema - '{ "installers": [],
+ "name": ""}'
+
+ See Installer for installer_schema
+
+.. code-block:: shell
+
+ from testapiclient.client import scenarios
+
+ scenario_client = scenarios.ScenariosClient(user='test', password='pass')
+ scenario_client.create(scenario_json)
+
+UPDATE
+""""""
+
+This method used to update the name of an existing scenario on the server.
+The user should provide the user parameter and the password
+parameter while initiating the ScenariosClient.
+
+Input for the function :
+
+ * scenario-name: name of the scenario which user want to update.
+ * scenario-json: Json object of the scenario
+
+.. NOTE::
+ * scenario_name
+ * scenario_update_json schema - '{"name": ""}'
+
+.. code-block:: shell
+
+ from testapiclient.client import scenarios
+
+ scenario_client = scenarios.ScenariosClient(user='test', password='pass')
+ scenario_client.update(scenario_name, scenario_update_json)
+
+DELETE
+""""""
+
+This method used to delete an existing scenario on the server.
+The user should provide the user parameter and the password
+parameter while initiating the ScenariosClient.
+
+Input for the function :
+
+ * scenario_name: name of the scenario which user want to delete.
+
+.. code-block:: shell
+
+ from testapiclient.client import scenarios
+
+ scenario_client = scenarios.ScenariosClient(user='test', password='pass')
+ scenario_client.delete('scenario_name')
+
+Scenario Installer
+^^^^^^^^^^^^^^^^^^
+
+CREATE
+""""""
+
+This method used to create an installer under a scenario
+on the server. The user should provide the user parameter
+and the password parameter while initiating the InstallersClient.
+
+Input for the function :
+ * scenario_name
+ * installer-json : Json object of the installer
+
+.. NOTE::
+ installer_json schema - '{ "versions": [],
+ "installer": ""}'
+
+ See version for version_schema
+
+.. code-block:: shell
+
+ from testapiclient.client import installers
+
+ installer_client = installers.InstallersClient(user='test', password='pass')
+ installer_client.create(scenario_name, installer_json)
+
+UPDATE
+""""""
+
+This method used to update the all existing installers of a scenario
+The user should provide the user parameter and the password
+parameter while initiating the InstallersClient.
+
+Input for the function :
+
+ * scenario_name
+ * installer-json: Json object of the installer
+
+.. NOTE::
+ * scenario_name
+ * installer_json schema - [{ "versions": [], "installer": ""}]
+
+.. code-block:: shell
+
+ from testapiclient.client import installers
+
+ installer_client = installers.InstallersClient(user='test', password='pass')
+ installer_client.update(scenario_name, installer_update_json)
+
+DELETE
+""""""
+
+This method used to delete existing installers from a scenario.
+on the server.
+The user should provide the user parameter and the password
+parameter while initiating the InstallersClient.
+
+Input for the function :
+ * scenario_name
+ * installer_names: names of the installer which user want to delete.
+
+.. code-block:: shell
+
+ from testapiclient.client import installers
+
+ installer_client = installers.InstallersClient(user='test', password='pass')
+ installer_client.delete(scenario_name, installer_names)
+
+Scenario Version
+^^^^^^^^^^^^^^^^
+
+CREATE
+""""""
+
+This method used to create a version under a scenario
+on the server. The user should provide the user parameter
+and the password parameter while initiating the VersionsClient.
+
+Input for the function :
+
+ * scenario_name
+ * installer_name
+ * version-json : Json object of the version
+
+.. NOTE::
+ version_json schema - '{ "projects": [], "owner": "",
+ "version": ""}'
+
+ See version for version_schema
+
+.. code-block:: shell
+
+ from testapiclient.client import versions
+
+ version_client = versions.VersionsClient(user='test', password='pass')
+ version_client.create(scenario_name, installer_name, version_json)
+
+UPDATE
+""""""
+
+This method used to update the all existing versions of a scenario
+The user should provide the user parameter and the password
+parameter while initiating the VersionsClient.
+
+Input for the function :
+
+ * scenario_name
+ * installer_name
+ * version-json: Json object of the version
+
+.. NOTE::
+ * scenario_name
+ * version_json schema - [{ "projects": [], "owner": "", "version": ""}]
+
+.. code-block:: shell
+
+ from testapiclient.client import versions
+
+ version_client = versions.VersionsClient(user='test', password='pass')
+ version_client.update(scenario_name, installer_name, version_update_json)
+
+DELETE
+""""""
+
+This method used to delete existing versions from a scenario.
+on the server.
+The user should provide the user parameter and the password
+parameter while initiating the VersionsClient.
+
+Input for the function :
+ * scenario_name
+ * installer_name
+ * version_names: names of the version which user want to delete.
+
+.. code-block:: shell
+
+ from testapiclient.client import versions
+
+ version_client = versions.VersionsClient(user='test', password='pass')
+ version_client.delete(scenario_name, installer_name, version_names)
+
+Scenario Project
+^^^^^^^^^^^^^^^^
+
+CREATE
+""""""
+
+This method used to create a project under a scenario
+on the server. The user should provide the user parameter
+and the password parameter while initiating the ProjectsClient.
+
+Input for the function :
+
+ * scenario_name
+ * installer_name
+ * version_name
+ * project-json : Json object of the project
+
+.. NOTE::
+ project_json schema - '{ "scores": [], "trust_indcators": [],
+ "customs": [], "project": ""}'
+
+ See project for project_schema
+
+.. code-block:: shell
+
+ from testapiclient.client import projects
+
+ project_client = projects.ProjectsClient(user='test', password='pass')
+ project_client.create(scenario_name, installer_name, version_name, project_json)
+
+UPDATE
+""""""
+
+This method used to update the all existing projects of a scenario
+The user should provide the user parameter and the password
+parameter while initiating the ProjectsClient.
+
+Input for the function :
+
+ * scenario_name
+ * installer_name
+ * version_name
+ * project-json: Json object of the project
+
+.. NOTE::
+ * scenario_name
+ * project_json schema - [{"scores": [], "trust_indcators": [], "customs": [], "project": ""}]
+
+.. code-block:: shell
+
+ from testapiclient.client import projects
+
+ project_client = projects.ProjectsClient(user='test', password='pass')
+ project_client.update(scenario_name, installer_name, version_name, project_update_json)
+
+DELETE
+""""""
+
+This method used to delete existing projects from a scenario.
+on the server.
+The user should provide the user parameter and the password
+parameter while initiating the ProjectsClient.
+
+Input for the function :
+ * scenario_name
+ * installer_name
+ * version_name
+ * project_names: names of the project which user want to delete.
+
+.. code-block:: shell
+
+ from testapiclient.client import projects
+
+ project_client = projects.ProjectsClient(user='test', password='pass')
+ project_client.delete(scenario_name, installer_name, version_name, project_names)
+
+Scenario Custom
+^^^^^^^^^^^^^^^
+
+CREATE
+""""""
+
+This method used to create a custom under a scenario
+on the server. The user should provide the user parameter
+and the password parameter while initiating the CustomsClient.
+
+Input for the function :
+
+ * scenario_name
+ * installer_name
+ * version_name
+ * project_name
+ * custom : List of Customs
+
+.. NOTE::
+ * scenario_name
+ * custom schema - ["List of Strings"]
+
+ See custom for custom_schema
+
+.. code-block:: shell
+
+ from testapiclient.client import customs
+
+ custom_client = customs.CustomsClient(user='test', password='pass')
+ custom_client.create(scenario_name, installer_name, version_name,
+ project_name, custom_json)
+
+UPDATE
+""""""
+
+This method used to update the all existing customs of a scenario
+The user should provide the user parameter and the password
+parameter while initiating the CustomsClient.
+
+Input for the function :
+
+ * scenario_name
+ * installer_name
+ * version_name
+ * project_name
+ * custom : List of Customs
+
+.. NOTE::
+ * scenario_name
+ * custom schema - ["List of Strings"]
+
+.. code-block:: shell
+
+ from testapiclient.client import customs
+
+ custom_client = customs.CustomsClient(user='test', password='pass')
+ custom_client.update(scenario_name, installer_name, version_name,
+ project_name custom)
+
+DELETE
+""""""
+
+This method used to delete existing customs from a scenario.
+on the server.
+The user should provide the user parameter and the password
+parameter while initiating the CustomsClient.
+
+Input for the function :
+ * scenario_name
+ * installer_name
+ * version_name
+ * project_name
+ * custom: custom which user want to delete.
+
+.. code-block:: shell
+
+ from testapiclient.client import customs
+
+ custom_client = customs.CustomsClient(user='test', password='pass')
+ custom_client.delete(scenario_name, installer_name, version_name,
+ project_name, customs)
+
+Scenario Scores
+^^^^^^^^^^^^^^^
+
+CREATE
+""""""
+
+This method used to create a score under a scenario
+on the server. The user should provide the user parameter
+and the password parameter while initiating the ScoresClient.
+
+Input for the function :
+
+ * scenario_name
+ * installer_name
+ * version_name
+ * project_name
+ * score_json : Schema for the score
+
+.. NOTE::
+ * scenario_name
+ * score_json schema - '{ "date": "", "score": ""}'
+
+ See score for score_schema
+
+.. code-block:: shell
+
+ from testapiclient.client import scores
+
+ score_client = scores.ScoresClient(user='test', password='pass')
+ score_client.create(scenario_name, installer_name, version_name,
+ project_name, score_json)
+
+Scenario TrustIndicator
+^^^^^^^^^^^^^^^^^^^^^^^
+
+CREATE
+""""""
+
+This method used to create a trust indicator under a scenario
+on the server. The user should provide the user parameter
+and the password parameter while initiating the TrustIndicatorsClient.
+
+Input for the function :
+
+ * scenario_name
+ * installer_name
+ * version_name
+ * project_name
+ * trust_indicator_json : Schema for the trust_indicator
+
+.. NOTE::
+ * scenario_name
+ * trust_indicator_json schema - '{ "date": "", "status": ""}'
+
+ See trust_indicator for trust_indicator_schema
+
+.. code-block:: shell
+
+ from testapiclient.client import trust_indicators
+
+ trust_indicator_client = trust_indicators.TrustIndicatorsClient(user='test', password='pass')
+ trust_indicator_client.create(scenario_name, installer_name, version_name,
+ project_name, trust_indicator_json) \ No newline at end of file
diff --git a/testapi/docs/developer/devguide/testapi-client.rst b/testapi/docs/developer/devguide/testapi-client.rst
index ab4c8e8..5ba5df3 100644
--- a/testapi/docs/developer/devguide/testapi-client.rst
+++ b/testapi/docs/developer/devguide/testapi-client.rst
@@ -6,5 +6,859 @@
TestAPI client
==============
-.. toctree::
- :maxdepth: 2
+TestAPIClient is a command-line client for TestAPI that
+brings the command set for pod, project, testcase, results,
+deploy result and scenario together in a single shell with a uniform command
+structure.
+
+
+Installation
+------------
+
+User can install this client from the source.
+
+.. code-block:: shell
+
+ python install testapi/testapi-client/setup.py install
+
+After the installation, user has to set the environment variables
+
+.. code-block:: shell
+
+ source testapi/testapi-client/etc/client.creds
+
+
+Authentication Process
+----------------------
+
+User needs to provide the username and the password with the testapi
+command.
+
+.. code-block:: shell
+
+ $ testapi -u [username] -p [password]
+ (testapi) pod create
+
+
+or
+
+.. code-block:: shell
+
+ testapi pode create -u [username] -p [password] [pod-schema]
+
+First one, user can continue the progress after the authentication.
+cli will create a new session to handle the request.
+
+In second one, cli won't create a session. one time command.
+
+Token is also used for the authorization purpose. User has to obtain the
+valid token from the TestAPI comminity and set it in the following file
+: **testapi/testapi-client/etc/client.creds**
+
+.. code-block:: shell
+
+ source testapi/testapi-client/etc/client.creds
+
+
+Command Structure
+-----------------
+
+TestAPIClient follows a common command Structure.
+
+.. code-block:: shell
+
+ testapi [resource-name] [function] [-u] [username] [-p] [password]
+ [command-arguments]
+
+.. NOTE::
+ resource-name : include first order parent name and resource name.
+
+ example:
+ scenario installer, scenario version, scenario project, scenario custom,
+ scenario trustindicator, scenario score, pod , project, testcase, result,
+ deployresult and scenario.
+
+.. NOTE::
+ -u and -p are optional commands. The user can decide on them.
+
+There are many arguments for each commands. User can get them using
+help command in the cli.
+
+.. code-block:: shell
+
+ pod create --help/-h
+
+Pod
+^^^
+
+Create
+""""""
+
+Authentication required
+
+.. code-block:: shell
+
+ testapi pod create [-u] [username] [-p] [password] [pod-schema]
+
+or
+
+.. code-block:: shell
+
+ $ testapi [-u] [username] [-p] [password]
+ (testapi) pod create [pod-schema]
+
+.. NOTE::
+ pod-schema - '{"role": "", "name": "", "details": "", "mode": ""}'
+
+Get
+"""
+
+Authentication is not required
+
+.. code-block:: shell
+
+ testapi pod get [-name] [key-word]
+
+.. NOTE::
+ -name is not mandatory. The user can use the -name option to reduce the
+ search result otherwise they will get the details about all pods.
+
+Get one
+"""""""
+
+Authentication is not required
+
+.. code-block:: shell
+
+ testapi pod getone [name-keyword]
+
+.. NOTE::
+ name-keyword is mandatory.
+
+
+Delete
+""""""
+
+Authentication is required
+
+.. code-block:: shell
+
+ testapi pod delete [-u] [username] [-p] [password] [pod-name]
+
+or
+
+.. code-block:: shell
+
+ $ testapi [-u] [username] [-p] [password]
+ (testapi) pod delete [pod-name]
+
+.. NOTE::
+ pod-name is mandatory.
+
+
+Project
+^^^^^^^
+
+Create
+""""""
+
+Authentication required
+
+.. code-block:: shell
+
+ testapi project create [-u] [username] [-p] [password] [project-schema]
+
+or
+
+.. code-block:: shell
+
+ $ testapi [-u] [username] [-p] [password]
+ (testapi) project create [project-schema]
+
+.. NOTE::
+ project-schema - '{"description": "", "name": ""}'
+
+
+Get
+"""
+
+Authentication is not required
+
+.. code-block:: shell
+
+ testapi project get [-name] [key-word]
+
+.. NOTE::
+ -name is not mandatory. The user can use the -name option to reduce the
+ search result otherwise they will get the details about all projects.
+
+Get one
+"""""""
+
+Authentication is not required
+
+.. code-block:: shell
+
+ testapi project getone [name-keyword]
+
+.. NOTE::
+ name-keyword is mandatory.
+
+Update
+""""""
+
+Authentication required
+
+.. code-block:: shell
+
+ testapi project put [-u] [username] [-p] [password] [project-name]
+ [project-schema]
+
+or
+
+.. code-block:: shell
+
+ $ testapi [-u] [username] [-p] [password]
+ (testapi) project put [project-name] [project-schema]
+
+.. NOTE::
+ project-schema - '{"name": "", "description": ""}'
+
+Delete
+""""""
+
+Authentication is required
+
+.. code-block:: shell
+
+ testapi project delete [-u] [username] [-p] [password] [project-name]
+
+or
+
+.. code-block:: shell
+
+ $ testapi [-u] [username] [-p] [password]
+ (testapi) project delete [project-name]
+
+.. NOTE::
+ project-name is mandatory.
+
+Testcase
+^^^^^^^^
+
+Create
+""""""
+
+Authentication required
+
+.. code-block:: shell
+
+ testapi testcase create [-u] [username] [-p] [password]
+ [--project-name] [testcase-schema]
+
+or
+
+.. code-block:: shell
+
+ $ testapi [-u] [username] [-p] [password]
+ (testapi) testcase create [--project-name] [testcase-schema]
+
+.. NOTE::
+ testcase-schema - '{"run": "", "name": "", "ci_loop": "", "tags": "",
+ "url": "", "catalog_description": "", "tier": "",
+ "dependencies": "", "version": "", "criteria": "",
+ "domains": "", "trust": "", "blocking": "",
+ "description": ""}'
+
+
+Get
+"""
+
+Authentication is not required
+
+.. code-block:: shell
+
+ testapi testcase get [--project-name]
+
+.. NOTE::
+ --project-name is mandatory.
+
+Get one
+"""""""
+
+Authentication is not required
+
+.. code-block:: shell
+
+ testapi testcase getone [--project-name] [name]
+
+.. NOTE::
+ name and project-name are mandatory.
+
+Update
+""""""
+
+Authentication required
+
+.. code-block:: shell
+
+ testapi testcase put [-u] [username] [-p] [password] [--project-name]
+ [name] [testcase-schema]
+
+or
+
+.. code-block:: shell
+
+ $ testapi [-u] [username] [-p] [password]
+ (testapi) testcase put [--project-name] [name] [testcase-schema]
+
+.. NOTE::
+ testcase-schema - '{"run": "", "name": "", "ci_loop": "", "tags": "",
+ "url": "", "catalog_description": "", "tier": "",
+ "dependencies": "", "version": "", "criteria": "",
+ "domains": "", "trust": "", "blocking": "",
+ "description": ""}
+
+
+Result
+^^^^^^^
+
+Create
+""""""
+
+Token is required. Set token as an environment variable.
+
+.. code-block:: shell
+
+ testapi result create [-u] [username] [-p] [password] [result-schema]
+
+or
+
+.. code-block:: shell
+
+ $ testapi [-u] [username] [-p] [password]
+ (testapi) result create [result-schema]
+
+.. NOTE::
+ result-schema - '{"project_name": "", "scenario": "", "stop_date": "",
+ "case_name": "", "build_tag": "", "version": "",
+ "pod_name": "", "criteria": "", "installer": "",
+ "start_date": "", "details": ""}'
+
+
+Get
+"""
+
+Authentication is not required
+
+.. code-block:: shell
+
+ testapi result get [-cli-arguments] [arguments-value]
+
+.. NOTE::
+ List of commandline arguments
+
+ * -case : Search results using tesetcase
+ * -build-tag : Search results using build tag
+ * -from : Search results using from date
+ * -last : Search results using last date
+ * -scenario : Search results using scenario
+ * -period : Search results using period
+ * -project : Search results using project
+ * -to : Search results using to
+ * ---version : Search results using version
+ * -criteria : Search results using criteria
+ * -installer : Search results using installer
+ * -pod : Search results using pod
+ * -page : Search results using page
+
+Get one
+"""""""
+
+Token is required. Set token as an environment variable.
+
+.. code-block:: shell
+
+ testapi result getone [result_id]
+
+.. NOTE::
+ result_id is mandatory.
+
+Deploy Result
+^^^^^^^^^^^^^
+
+Create
+""""""
+
+Token is required. Set token as an environment variable.
+
+
+.. code-block:: shell
+
+ testapi deployresult [-u] [username] [-p] [password]
+ [--project-name] [deployresult-schema]
+
+or
+
+.. code-block:: shell
+
+ $ testapi [-u] [username] [-p] [password]
+ (testapi) deployresult create [deployresult-schema]
+
+.. NOTE::
+ deployresult-schema - '{"run": "", "name": "", "ci_loop": "", "tags": "",
+ "url": "", "catalog_description": "", "tier": "",
+ "dependencies": "", "version": "", "criteria": "",
+ "domains": "", "trust": "", "blocking": "",
+ "description": ""}'
+
+
+Get
+"""
+
+Authentication is not required
+
+.. code-block:: shell
+
+ testapi deployresult get [-cli-arguments] [arguments-value]
+
+.. NOTE::
+ List of command line arguments
+
+ * -job-name : Search results using job
+ * -build-id : Search results using build id
+ * -from : Search results using from date
+ * -last : Search results using last date
+ * -scenario : Search results using scenario
+ * -period : Search results using period
+ * -to : Search results using to
+ * ---version : Search results using version
+ * -criteria : Search results using criteria
+ * -installer : Search results using installer
+ * -pod-name : Search results using pod
+ * -page : Search results using page
+
+Get one
+"""""""
+
+Authentication is not required
+
+.. code-block:: shell
+
+ testapi deployresult getone [deployresult_id]
+
+.. NOTE::
+ deployresult_id is mandatory.
+
+
+Scenario
+^^^^^^^^
+
+Create
+""""""
+
+Authentication required
+
+.. code-block:: shell
+
+ testapi scenario create [-u] [username] [-p] [password] [scenario-schema]
+
+or
+
+.. code-block:: shell
+
+ $ testapi [-u] [username] [-p] [password]
+ (testapi) scenario create [scenario-schema]
+
+.. NOTE::
+ scenario-schema - '{"name": "", "installers": []}'
+
+
+Get
+"""
+
+Authentication is not required
+
+.. code-block:: shell
+
+ testapi scenario get [-name] [key-word]
+
+.. NOTE::
+
+ user can use some attributes to reduce the search results. These are not
+ mandatory.
+
+ * -name : Backend will use regular expression to search.
+ * -project : Search using project name
+ * -installer : Search using installer name
+ * -version : Search using version name
+
+Get one
+"""""""
+
+Authentication is not required
+
+.. code-block:: shell
+
+ testapi scenario getone [name-keyword]
+
+.. NOTE::
+ name-keyword is mandatory.
+
+Update
+""""""
+
+Authentication required
+
+.. code-block:: shell
+
+ testapi scenario put [-u] [username] [-p] [password] [scenario-name]
+ [scenario-schema]
+
+or
+
+.. code-block:: shell
+
+ $ testapi [-u] [username] [-p] [password]
+ (testapi) scenario put [scenario-name] [scenario-schema]
+
+.. NOTE::
+ scenario-schema - '{"name": "", "installers": []}'
+
+Delete
+""""""
+
+Authentication is required
+
+.. code-block:: shell
+
+ testapi scenario delete [-u] [username] [-p] [password] [scenario-name]
+
+or
+
+.. code-block:: shell
+
+ $ testapi [-u] [username] [-p] [password]
+ (testapi) scenario delete [scenario-name]
+
+.. NOTE::
+ scenario-name is mandatory.
+
+Scenario installer
+^^^^^^^^^^^^^^^^^^
+
+Create
+""""""
+
+Authentication required
+
+.. code-block:: shell
+
+ testapi scenario installer create [-u] [username] [-p] [password]
+ --scenario-name [scenario-name] [installer-schema]
+
+or
+
+.. code-block:: shell
+
+ $ testapi [-u] [username] [-p] [password]
+ (testapi) scenario installer create --scenario-name [scenario-name]
+ [installer-schema]
+
+.. NOTE::
+ installer-schema - '{"installer": "", "versions": []}'
+
+Update
+""""""
+
+Authentication required
+
+.. code-block:: shell
+
+ testapi scenario installer put [-u] [username] [-p] [password]
+ --scenario-name [scenario-name] [installer-schema]
+
+or
+
+.. code-block:: shell
+
+ $ testapi [-u] [username] [-p] [password]
+ (testapi) scenario put --scenario-name [scenario-name] [installer-schema]
+
+.. NOTE::
+ scenario-schema - '{"installer": "", "installers": []}'
+
+Delete
+""""""
+
+Authentication is required
+
+.. code-block:: shell
+
+ testapi scenario delete [-u] [username] [-p] [password] --scenario-name
+ [scenario-name] [name]
+
+or
+
+.. code-block:: shell
+
+ $ testapi [-u] [username] [-p] [password]
+ (testapi) scenario delete --scenario-name [scenario-name] [name]
+
+Scenario version
+^^^^^^^^^^^^^^^^
+
+Create
+""""""
+
+Authentication required
+
+.. code-block:: shell
+
+ testapi scenario version create [-u] [username] [-p] [password]
+ --scenario-name [scenario-name] --installer [installer] [version-schema]
+
+or
+
+.. code-block:: shell
+
+ $ testapi [-u] [username] [-p] [password]
+ (testapi) scenario installer create --scenario-name [scenario-name]
+ --installer [installer] [version-schema]
+
+.. NOTE::
+ installer-schema - '{"version": "", "owner": "", "projects": []}'
+
+Update
+""""""
+
+Authentication required
+
+.. code-block:: shell
+
+ testapi scenario installer put [-u] [username] [-p] [password]
+ --scenario-name [scenario-name] --installer [installer] [version-schema]
+
+or
+
+.. code-block:: shell
+
+ $ testapi [-u] [username] [-p] [password]
+ (testapi) scenario installer put --scenario-name [scenario-name]
+ --installer [installer] [installer-schema]
+
+.. NOTE::
+ scenario-schema - '{"version": "","owner": "", "projects": []}'
+
+Delete
+""""""
+
+Authentication is required
+
+.. code-block:: shell
+
+ testapi scenario installer delete [-u] [username] [-p] [password]
+ --scenario-name [scenario-name] --installer [installer] [name]
+
+or
+
+.. code-block:: shell
+
+ $ testapi [-u] [username] [-p] [password]
+ (testapi) scenario installer delete --scenario-name [scenario-name]
+ --installer [installer] [name]
+
+Scenario Project
+^^^^^^^^^^^^^^^^
+
+Create
+""""""
+
+Authentication required
+
+.. code-block:: shell
+
+ testapi scenario project create [-u] [username] [-p] [password]
+ --scenario-name [scenario-name] --installer [installer]
+ ---version [version] [project-schema]
+
+or
+
+.. code-block:: shell
+
+ $ testapi [-u] [username] [-p] [password]
+ (testapi) scenario project create --scenario-name [scenario-name]
+ --installer [installer] ---version [version] [project-schema]
+
+.. NOTE::
+ installer-schema - '{"scores": [],"customs": [], "trust_indicators": [],
+ project:""}'
+
+Update
+""""""
+
+Authentication required
+
+.. code-block:: shell
+
+ testapi scenario project put [-u] [username] [-p] [password]
+ --scenario-name [scenario-name] --installer [installer] ---version
+ [version] [project-schema]
+
+or
+
+.. code-block:: shell
+
+ $ testapi [-u] [username] [-p] [password]
+ (testapi) scenario project put --scenario-name [scenario-name] --installer
+ [installer] ---version [version] [project-schema]
+
+.. NOTE::
+ scenario-schema - '{"scores": [],"customs": [], "trust_indicators": [],
+ project:""}'
+
+Delete
+""""""
+
+Authentication is required
+
+.. code-block:: shell
+
+ testapi scenario project delete [-u] [username] [-p] [password]
+ --scenario-name [scenario-name] --installer [installer] ---version
+ [version] [name]
+
+or
+
+.. code-block:: shell
+
+ $ testapi [-u] [username] [-p] [password]
+ (testapi) scenario project delete --scenario-name [scenario-name]
+ --installer [installer] ---version [version] [name]
+
+Scenario Customs
+^^^^^^^^^^^^^^^^
+
+Create
+""""""
+
+Authentication required
+
+.. code-block:: shell
+
+ testapi scenario custom create [-u] [username] [-p] [password]
+ --scenario-name [scenario-name] --installer [installer]
+ ---version [version] --project [project] [customs]
+
+or
+
+.. code-block:: shell
+
+ $ testapi [-u] [username] [-p] [password]
+ (testapi) scenario custom create --scenario-name [scenario-name]
+ --installer [installer] ---version [version] --project [project] [customs]
+
+.. NOTE::
+
+ customs : Space sperated strings
+
+Update
+""""""
+
+Authentication required
+
+.. code-block:: shell
+
+ testapi scenario custom put [-u] [username] [-p] [password]
+ --scenario-name [scenario-name] --installer [installer] ---version
+ [version] --project [project] [customs]
+
+or
+
+.. code-block:: shell
+
+ $ testapi [-u] [username] [-p] [password]
+ (testapi) scenario custom put --scenario-name [scenario-name] --installer
+ [installer] ---version [version] --project [project] [customs]
+
+.. NOTE::
+
+ customs : Space sperated strings
+
+Delete
+""""""
+
+Authentication is required
+
+.. code-block:: shell
+
+ testapi scenario custom delete [-u] [username] [-p] [password]
+ --scenario-name [scenario-name] --installer [installer] ---version
+ [version] --project [project] [customs]
+
+or
+
+.. code-block:: shell
+
+ $ testapi [-u] [username] [-p] [password]
+ (testapi) scenario custom delete --scenario-name [scenario-name]
+ --installer [installer] ---version [version] --project [project]
+ [customs]
+
+.. NOTE::
+
+ customs : Space sperated strings
+
+Scenario Score
+^^^^^^^^^^^^^^
+
+Create
+""""""
+
+Authentication required
+
+.. code-block:: shell
+
+ testapi scenario score create [-u] [username] [-p] [password]
+ --scenario-name [scenario-name] --installer [installer]
+ ---version [version] --project [project] [score_schema]
+
+or
+
+.. code-block:: shell
+
+ $ testapi [-u] [username] [-p] [password]
+ (testapi) scenario score create --scenario-name [scenario-name]
+ --installer [installer] ---version [version] --project [project]
+ [score_schema]
+
+.. NOTE::
+
+ score_schema : '{"score": "", "date": ""}'
+
+Scenario TrustIndicators
+^^^^^^^^^^^^^^^^^^^^^^^^
+
+Create
+""""""
+
+Authentication required
+
+.. code-block:: shell
+
+ testapi scenario trustindicator create [-u] [username] [-p] [password]
+ --scenario-name [scenario-name] --installer [installer]
+ ---version [version] --project [project] [trustindicator_schema]
+
+or
+
+.. code-block:: shell
+
+ $ testapi [-u] [username] [-p] [password]
+ (testapi) scenario trustindicator create --scenario-name [scenario-name]
+ --installer [installer] ---version [version] --project [project]
+ [trustindicator_schema]
+
+.. NOTE::
+
+ trustindicator_schema : '{"status": "", "date": ""}' \ No newline at end of file
diff --git a/testapi/docs/developer/devguide/web-portal.rst b/testapi/docs/developer/devguide/web-portal.rst
index 62b2f17..8c4bc6c 100644
--- a/testapi/docs/developer/devguide/web-portal.rst
+++ b/testapi/docs/developer/devguide/web-portal.rst
@@ -6,5 +6,115 @@
Web portal
==========
-.. toctree::
- :maxdepth: 2
+**Web-portal of OPNFV Testapi**:
+
+This project aims to provide the web interface for the Testapi framework. It uses the Restful APIs
+of the testapi framework to provide front-end functionalities.
+
+If you are interested in how TestAPI looks like, please visit OPNFV's official `TestAPI Server`__
+
+.. __: http://testresults.opnfv.org/test
+
+Pre-requsites
+=============
+
+In the web portal, we are using AngularJS(1.3.15) as the frontend framework with Bootstrap(v3) CSS.
+
+Running locally
+===============
+
+Installation
+^^^^^^^^^^^^
+
+Web portal will be installed with the testapi framework. No extra installation.
+
+.. code-block:: shell
+
+ python setup.py install
+
+Start Server
+^^^^^^^^^^^^
+
+.. code-block:: shell
+
+ *opnfv-testapi [--config-file <config.ini>]*
+
+If --config-file is provided, the specified configuration file will be employed
+when starting the server, or else /etc/opnfv_testapi/config.ini will be utilized
+by default.
+
+After executing the command successfully, a TestAPI server will be started on
+port 8000, to visit web portal, please access http://hostname:8000
+
+Test
+===============
+
+There are few external requirements for the testing.
+They are
+
+1. npm : node package manager
+ you can get the installation package for nodejs from the official `website`__
+
+ .. __: https://nodejs.org/en/
+
+2. grunt cli : Automation tool
+
+.. code-block:: shell
+
+ npm install -g grunt-cli
+
+After installing global dependencies, you have to install the required local node modules.
+
+.. code-block:: shell
+
+ npm install
+
+**Running tests**
+
+.. code-block:: shell
+
+ grunt e2e
+
+Authentication
+==============
+
+The web portal is using Linux identity server as the Central Authentication Service. The following
+diagram will explain the authentication process.
+
+.. image:: /images/CAS-sequence.jpg
+ :width: 600
+ :alt: Workflow of the Athentication
+
+When a new user initially logs into an application they won't have established a
+session with the application. Instead of displaying a login form asking for the username and
+password, the application (via the CAS Client) will redirect the browser to the linux foundation
+login page. Linux foundation identity server then authenticates the user. If the authentication
+fails, the Linux foundation login page is displayed again with an error message. So until
+authentication succeeds, the user will not be returned to the application.
+
+Authorization
+=============
+
+TestAPI has 3 level authorization layer. They are
+
+**Public**
+
+The public can view the resources(pod, project, testcase, result, deploy result, scenario).
+They do not have the access to create, delete or modify the resources.
+
+**User - Contributors**
+
+Contributors level user can view all the resources(pod, project, testcase, result, deploy result,
+scenario). They can create/delete/modify pod and scenario.
+
+They do not have the access to create project or testcase.
+
+**User - Submitter**
+
+Submitter level user can view all the resources(pod, project, testcase, result, deploy result,
+scenario). They can create/delete/modify pod and scenario.
+
+If user want to create/modify/delete a project or testcase then user has to be in the Submitter
+group for that specific project.
+
+Currently, we can't create/modify/delete results or deploy results from the web portal. \ No newline at end of file
diff --git a/testapi/docs/internship/webportal.rst b/testapi/docs/internship/webportal.rst
new file mode 100644
index 0000000..1ea9c19
--- /dev/null
+++ b/testapi/docs/internship/webportal.rst
@@ -0,0 +1,169 @@
+.. This work is licensed under a Creative Commons Attribution 4.0 International License.
+.. http://creativecommons.org/licenses/by/4.0
+
+
+*****************************
+Web Portal for OPNFV Test API
+*****************************
+
+Author: Tharmarajasingam Thuvarakan Mentors: S. Feng, J.Lausuch, M.Richomme
+
+Abstract
+========
+
+TestAPI is used by all the test projects to report results. It is also used to declare projects,
+test cases and labs. It is defined in the Functest developer guide. The internship aims to add web
+portal for TestAPI. The showcase user got through the web portal, will be more human-friendly
+compared to the swagger page. Also, internship aims to build a python client to reduce the workload.
+Python client can be used as a python module.
+
+Overview
+========
+
+The internship time period was from Oct 9th to May 18th. The project proposal page is here [1]_.
+The intern project was assigned to Thuvarakan and was mentored by S. Feng, J.Lausuch, M.Richomme.
+The link to the patches submitted is [2]_. The internship was successfully completed and the
+documentation is as follows.
+
+
+
+Problem Statement
+=================
+
+The following were to be accomplished within the internship time frame.
+
+* Redesign the website theme
+
+ Change the existing theme of the frontend and design a unified theme.
+
+* Add separate pages to each resource
+
+ Create a separate web page for each resource in the new theme.
+
+* Implement all the functionalities in the frontend
+
+ Implement the backend functionalities in the frontend for each
+ resource.
+
+* Authentication for testapiclient
+
+ Implement the authentication functionality in the testapiclient.
+
+* Add all functionalities to testapiclient
+
+ Implement the backend functionalities in the testapiclient for each
+ resource.
+
+* Add support to testapiclient as a python module
+
+ Convert the testapiclient from CLI only to CLI and python module
+ mode.
+
+
+Curation Phase
+==============
+
+The curation phase was the first 4 to 8 weeks of the internship. This phase
+was to get familiar with the testapi code and functionality and propose the
+solutions/tools for the tasks mentioned above.
+
+These are the tools, we proposed for the solutions.
+
+* protractor: An end-to-end test framework for Angular and AngularJS applications
+
+* grunt: A Javascript task runner, a tool used to automatically perform
+ frequent tasks such as minification, compilation, unit testing, and
+ linting.
+
+* cliff: Command Line Interface Formulation Framework.
+
+
+Schedule
+========
+
+=================== ========================================================
+ Date Comment
+=================== ========================================================
+10th Oct ~17th Oct Setting up the development environment, design decisions
+17th Oct ~ 24th Oct Pod web portal CRUD
+24th Oct ~ 31st Oct Projects web portal CRUD
+13st Oct ~ 7th Nov Test cases web portal CRUD
+7th Nov ~ 14th Nov Results web portal R
+14th Nov ~ 21st Nov Results web portal R
+21st Nov ~ 28th Nov Scenario web portal CRUD
+28th Nov ~ 5th Dec Testapi-client framework
+5th Dec ~ 12nd Dec Pods testapi-client CRUD
+12nd Dec ~ 19th Dec Projects testapi-client CRUD
+19th Dec ~ 26th Dec Test cases testapi-client CRUD
+26th Dec ~ 9th Jan Results testapi-client CRUD
+9th Jan ~ 23rd Jan Scenario testapi-client CRUD
+23rd Jan ~ 6th Mar Bugfix in the frontend and testapiclient
+6th Mar ~ 20th Mar Convert testapiclient to python module
+20th Mar ~ 3rd Apr Testing the python module
+3rd Apr ~ 9th May Documentation & Bugfix
+=================== ========================================================
+
+
+FAQ
+===
+
+
+Frontend
+********
+
+1. How to add a new test file for the frontend?
+
+ * Frontend test is handled by protractor [3]_ and
+ automated by the grunt [4]_. All the tests are located in
+ "opnfv_testapi/tests/UI/e2e".
+ First, create a text file in the e2e folder. Then add it to the spec
+ list in the "opnfv_testapi/ui/Gruntfile.js".
+
+
+2. How to test application's functionalities interactively?
+
+ * Application requires authentication for many functionalities.
+ It will cause time for the developer to check the functionalities.
+ Developers can use the application in the authentication false mode.
+ To do that, first, change the authenticate to false in the
+ "etc/config.ini" file then change the authenticate to false in
+ the "opnfv_testapi/ui/config.json" file.
+
+
+3. Browser does not reflect the code changes, what is it mean?
+
+ * Browser is saving the caches for fast reloadings. Sometime browser
+ won't reload the new changes, to solve that we have to clear the browser
+ caches.
+
+
+Testapiclient
+*************
+
+1. How to add a new test file for testapiclient?
+
+ * Frontend test is handled by testtools [5]_ and automated by tox [6]_.
+ All the tests are located in "testapi-client/tests/unit". Create a text
+ file in the unit folder. The name of the test file should start with
+ 'test\_'. It will automatically add that test file to queue.
+
+
+2. Difference between client and cli?
+
+ * Client is used to importing testapiclient as a python module.
+ The cli folder contained the command line interface for the testapiclient.
+
+References
+==========
+
+.. [1] https://wiki.opnfv.org/display/DEV/Intern+Project%3A+Web+Portal+for+OPNFV+Test+API
+
+.. [2] https://gerrit.opnfv.org/gerrit/#/q/status:merged+owner:%22Thuvarakan+Tharmarajasingam+%253Ctharma.thuva%2540gmail.com%253E%22
+
+.. [3] https://www.protractortest.org/
+
+.. [4] https://gruntjs.com
+
+.. [5] https://github.com/testing-cabal/testtools
+
+.. [6] https://tox.readthedocs.io/en/latest/# \ No newline at end of file
diff --git a/testapi/opnfv_testapi/common/check.py b/testapi/opnfv_testapi/common/check.py
index 18dc67d..fdc527f 100644
--- a/testapi/opnfv_testapi/common/check.py
+++ b/testapi/opnfv_testapi/common/check.py
@@ -31,16 +31,22 @@ def is_authorized(method):
raises.Unauthorized(message.not_lfid())
if method.__name__ == "_create":
kwargs['creator'] = testapi_id
- if self.table in ['projects']:
+ if self.table in ['projects', 'testcases']:
+ map_name = {
+ 'projects': 'name',
+ 'testcases': 'project_name'
+ }
+ group = "opnfv-gerrit-{}-submitters"
query = kwargs.get('query')
if type(query) is not dict:
query_data = query()
else:
- if self.json_args is None or 'name' not in self.json_args:
+ if (self.json_args is None or
+ map_name[self.table] not in self.json_args):
query_data = query
else:
query_data = self.json_args
- group = "opnfv-gerrit-" + query_data['name'] + "-submitters"
+ group = group.format(query_data[map_name[self.table]])
if group not in user_info['groups']:
raises.Unauthorized(message.no_permission())
ret = yield gen.coroutine(method)(self, *args, **kwargs)
@@ -59,12 +65,14 @@ def is_reource_tied(method):
}
if self.table in tied_maps:
if method.__name__ == '_update':
- if 'name' not in self.json_args:
- ret = yield gen.coroutine(method)(self, *args, **kwargs)
- raise gen.Return(ret)
+ if 'name' in self.json_args:
+ if self.json_args['name'] == kwargs.get('query')['name']:
+ ret = yield gen.coroutine(method)(
+ self, *args, **kwargs)
+ raise gen.Return(ret)
query_data[tied_maps[self.table][1]] = kwargs.get('query')['name']
- data = yield dbapi.db_find_one(tied_maps[self.table][0],
- query_data)
+ data = yield dbapi.db_find_one(
+ tied_maps[self.table][0], query_data)
if data:
raises.Unauthorized(message.tied_with_resource())
ret = yield gen.coroutine(method)(self, *args, **kwargs)
diff --git a/testapi/opnfv_testapi/handlers/sign_handlers.py b/testapi/opnfv_testapi/handlers/sign_handlers.py
index 7540662..2039971 100644
--- a/testapi/opnfv_testapi/handlers/sign_handlers.py
+++ b/testapi/opnfv_testapi/handlers/sign_handlers.py
@@ -46,7 +46,7 @@ class SigninReturnHandler(SignBaseHandler):
dbapi.db_update(self.table, q_user, login_user)
self.clear_cookie(constants.TESTAPI_ID)
- self.set_secure_cookie(constants.TESTAPI_ID, user)
+ self.set_secure_cookie(constants.TESTAPI_ID, user, 1)
self.redirect(url=CONF.ui_url)
diff --git a/testapi/opnfv_testapi/tests/UI/e2e/authenticateFalseSpec.js b/testapi/opnfv_testapi/tests/UI/e2e/authenticateFalseSpec.js
index 3212b86..6b9a2bf 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([
{
@@ -250,7 +250,7 @@ describe('testing the scenarios page for anonymous user', function () {
browser.get(baseURL+"#/scenarios/test-scenario");
var EC = browser.ExpectedConditions;
browser.wait(EC.urlContains(baseURL+ '#/scenarios/test-scenario'), 10000);
- var buttonAdd = element(by.xpath('//*[@id="ng-app"]/body/div/div[1]/div/table/tbody/tr[4]/td[2]/div[2]/button'))
+ var buttonAdd = element(by.xpath('//*[@id="ng-app"]/body/div/div[1]/div/table/tbody/tr[5]/td[2]/div[2]/button'))
expect(buttonAdd.isDisplayed()).toBe(true);
});
@@ -258,9 +258,9 @@ describe('testing the scenarios page for anonymous user', function () {
browser.get(baseURL+"#/scenarios/test-scenario");
var EC = browser.ExpectedConditions;
browser.wait(EC.urlContains(baseURL+ '#/scenarios/test-scenario'), 10000);
- var installersShow = element(by.xpath('//*[@id="ng-app"]/body/div/div[1]/div/table/tbody/tr[4]/td[2]/div[1]/a/p'))
+ var installersShow = element(by.xpath('//*[@id="ng-app"]/body/div/div[1]/div/table/tbody/tr[5]/td[2]/div[1]/a/p'))
installersShow.click();
- var installerDelete = element(by.xpath('//*[@id="ng-app"]/body/div/div[1]/div/table/tbody/tr[4]/td[2]/div[3]/div/table/tbody/tr[1]/td[3]/button'))
+ var installerDelete = element(by.xpath('//*[@id="ng-app"]/body/div/div[1]/div/table/tbody/tr[5]/td[2]/div[3]/div/table/tbody/tr[1]/td[3]/button'))
expect(installerDelete.isDisplayed()).toBe(true);
});
@@ -268,11 +268,11 @@ describe('testing the scenarios page for anonymous user', function () {
browser.get(baseURL+"#/scenarios/test-scenario");
var EC = browser.ExpectedConditions;
browser.wait(EC.urlContains(baseURL+ '#/scenarios/test-scenario'), 10000);
- var installersShow = element(by.xpath('//*[@id="ng-app"]/body/div/div[1]/div/table/tbody/tr[4]/td[2]/div[1]/a/p'))
+ var installersShow = element(by.xpath('//*[@id="ng-app"]/body/div/div[1]/div/table/tbody/tr[5]/td[2]/div[1]/a/p'))
installersShow.click();
- var installerShow = element(by.xpath('//*[@id="ng-app"]/body/div/div[1]/div/table/tbody/tr[4]/td[2]/div[3]/div/table/tbody/tr[1]/td[2]/a'))
+ var installerShow = element(by.xpath('//*[@id="ng-app"]/body/div/div[1]/div/table/tbody/tr[5]/td[2]/div[3]/div/table/tbody/tr[1]/td[2]/a'))
installerShow.click();
- var versionAdd = element(by.xpath('//*[@id="ng-app"]/body/div/div[1]/div/table/tbody/tr[4]/td[2]/div[3]/div/table/tbody/tr[2]/td[2]/div[2]/button'))
+ var versionAdd = element(by.xpath('//*[@id="ng-app"]/body/div/div[1]/div/table/tbody/tr[5]/td[2]/div[3]/div/table/tbody/tr[2]/td[2]/div[2]/button'))
versionAdd.click()
expect(versionAdd.isDisplayed()).toBe(true);
});
@@ -281,15 +281,15 @@ describe('testing the scenarios page for anonymous user', function () {
browser.get(baseURL+"#/scenarios/test-scenario");
var EC = browser.ExpectedConditions;
browser.wait(EC.urlContains(baseURL+ '#/scenarios/test-scenario'), 10000);
- var installersShow = element(by.xpath('//*[@id="ng-app"]/body/div/div[1]/div/table/tbody/tr[4]/td[2]/div[1]/a/p'))
+ var installersShow = element(by.xpath('//*[@id="ng-app"]/body/div/div[1]/div/table/tbody/tr[5]/td[2]/div[1]/a/p'))
installersShow.click();
- var installerShow = element(by.xpath('//*[@id="ng-app"]/body/div/div[1]/div/table/tbody/tr[4]/td[2]/div[3]/div/table/tbody/tr[1]/td[2]/a'))
+ var installerShow = element(by.xpath('//*[@id="ng-app"]/body/div/div[1]/div/table/tbody/tr[5]/td[2]/div[3]/div/table/tbody/tr[1]/td[2]/a'))
installerShow.click();
- var versionsShow = element(by.xpath('//*[@id="ng-app"]/body/div/div[1]/div/table/tbody/tr[4]/td[2]/div[3]/div/table/tbody/tr[2]/td[2]/div[1]/a/p'))
+ var versionsShow = element(by.xpath('//*[@id="ng-app"]/body/div/div[1]/div/table/tbody/tr[5]/td[2]/div[3]/div/table/tbody/tr[2]/td[2]/div[1]/a/p'))
versionsShow.click();
- var versionShow = element(by.xpath('//*[@id="ng-app"]/body/div/div[1]/div/table/tbody/tr[4]/td[2]/div[3]/div/table/tbody/tr[2]/td[2]/div[3]/div/table/tbody/tr[1]/td[2]/a'))
+ var versionShow = element(by.xpath('//*[@id="ng-app"]/body/div/div[1]/div/table/tbody/tr[5]/td[2]/div[3]/div/table/tbody/tr[2]/td[2]/div[3]/div/table/tbody/tr[1]/td[2]/a'))
versionShow.click()
- var versionDelete = element(by.xpath('//*[@id="ng-app"]/body/div/div[1]/div/table/tbody/tr[4]/td[2]/div[3]/div/table/tbody/tr[2]/td[2]/div[3]/div/table/tbody[1]/tr[1]/td[3]/button'))
+ var versionDelete = element(by.xpath('//*[@id="ng-app"]/body/div/div[1]/div/table/tbody/tr[5]/td[2]/div[3]/div/table/tbody/tr[2]/td[2]/div[3]/div/table/tbody[1]/tr[1]/td[3]/button'))
expect(versionDelete.isDisplayed()).toBe(true);
});
@@ -297,15 +297,15 @@ describe('testing the scenarios page for anonymous user', function () {
browser.get(baseURL+"#/scenarios/test-scenario");
var EC = browser.ExpectedConditions;
browser.wait(EC.urlContains(baseURL+ '#/scenarios/test-scenario'), 10000);
- var installersShow = element(by.xpath('//*[@id="ng-app"]/body/div/div[1]/div/table/tbody/tr[4]/td[2]/div[1]/a/p'))
+ var installersShow = element(by.xpath('//*[@id="ng-app"]/body/div/div[1]/div/table/tbody/tr[5]/td[2]/div[1]/a/p'))
installersShow.click();
- var installerShow = element(by.xpath('//*[@id="ng-app"]/body/div/div[1]/div/table/tbody/tr[4]/td[2]/div[3]/div/table/tbody/tr[1]/td[2]/a'))
+ var installerShow = element(by.xpath('//*[@id="ng-app"]/body/div/div[1]/div/table/tbody/tr[5]/td[2]/div[3]/div/table/tbody/tr[1]/td[2]/a'))
installerShow.click();
- var versionsShow = element(by.xpath('//*[@id="ng-app"]/body/div/div[1]/div/table/tbody/tr[4]/td[2]/div[3]/div/table/tbody/tr[2]/td[2]/div[1]/a/p'))
+ var versionsShow = element(by.xpath('//*[@id="ng-app"]/body/div/div[1]/div/table/tbody/tr[5]/td[2]/div[3]/div/table/tbody/tr[2]/td[2]/div[1]/a/p'))
versionsShow.click();
- var versionShow = element(by.xpath('//*[@id="ng-app"]/body/div/div[1]/div/table/tbody/tr[4]/td[2]/div[3]/div/table/tbody/tr[2]/td[2]/div[3]/div/table/tbody/tr[1]/td[2]/a'))
+ var versionShow = element(by.xpath('//*[@id="ng-app"]/body/div/div[1]/div/table/tbody/tr[5]/td[2]/div[3]/div/table/tbody/tr[2]/td[2]/div[3]/div/table/tbody/tr[1]/td[2]/a'))
versionShow.click()
- var projectAdd = element(by.xpath('//*[@id="ng-app"]/body/div/div[1]/div/table/tbody/tr[4]/td[2]/div[3]/div/table/tbody/tr[2]/td[2]/div[3]/div/table/tbody/tr[3]/td[2]/div[2]/button'))
+ var projectAdd = element(by.xpath('//*[@id="ng-app"]/body/div/div[1]/div/table/tbody/tr[5]/td[2]/div[3]/div/table/tbody/tr[2]/td[2]/div[3]/div/table/tbody/tr[3]/td[2]/div[2]/button'))
projectAdd.click()
expect(projectAdd.isDisplayed()).toBe(true);
});
@@ -314,17 +314,17 @@ describe('testing the scenarios page for anonymous user', function () {
browser.get(baseURL+"#/scenarios/test-scenario");
var EC = browser.ExpectedConditions;
browser.wait(EC.urlContains(baseURL+ '#/scenarios/test-scenario'), 10000);
- var installersShow = element(by.xpath('//*[@id="ng-app"]/body/div/div[1]/div/table/tbody/tr[4]/td[2]/div[1]/a/p'))
+ var installersShow = element(by.xpath('//*[@id="ng-app"]/body/div/div[1]/div/table/tbody/tr[5]/td[2]/div[1]/a/p'))
installersShow.click();
- var installerShow = element(by.xpath('//*[@id="ng-app"]/body/div/div[1]/div/table/tbody/tr[4]/td[2]/div[3]/div/table/tbody/tr[1]/td[2]/a'))
+ var installerShow = element(by.xpath('//*[@id="ng-app"]/body/div/div[1]/div/table/tbody/tr[5]/td[2]/div[3]/div/table/tbody/tr[1]/td[2]/a'))
installerShow.click();
- var versionsShow = element(by.xpath('//*[@id="ng-app"]/body/div/div[1]/div/table/tbody/tr[4]/td[2]/div[3]/div/table/tbody/tr[2]/td[2]/div[1]/a/p'))
+ var versionsShow = element(by.xpath('//*[@id="ng-app"]/body/div/div[1]/div/table/tbody/tr[5]/td[2]/div[3]/div/table/tbody/tr[2]/td[2]/div[1]/a/p'))
versionsShow.click();
- var versionShow = element(by.xpath('//*[@id="ng-app"]/body/div/div[1]/div/table/tbody/tr[4]/td[2]/div[3]/div/table/tbody/tr[2]/td[2]/div[3]/div/table/tbody/tr[1]/td[2]/a'))
+ var versionShow = element(by.xpath('//*[@id="ng-app"]/body/div/div[1]/div/table/tbody/tr[5]/td[2]/div[3]/div/table/tbody/tr[2]/td[2]/div[3]/div/table/tbody/tr[1]/td[2]/a'))
versionShow.click()
- var projectsShow = element(by.xpath('//*[@id="ng-app"]/body/div/div[1]/div/table/tbody/tr[4]/td[2]/div[3]/div/table/tbody/tr[2]/td[2]/div[3]/div/table/tbody/tr[3]/td[2]/div[1]/a'))
+ var projectsShow = element(by.xpath('//*[@id="ng-app"]/body/div/div[1]/div/table/tbody/tr[5]/td[2]/div[3]/div/table/tbody/tr[2]/td[2]/div[3]/div/table/tbody/tr[3]/td[2]/div[1]/a'))
projectsShow.click();
- var projectDelete = element(by.xpath('//*[@id="ng-app"]/body/div/div[1]/div/table/tbody/tr[4]/td[2]/div[3]/div/table/tbody/tr[2]/td[2]/div[3]/div/table/tbody/tr[3]/td[2]/div[3]/div/table/tbody[1]/tr[1]/td[3]/button'))
+ var projectDelete = element(by.xpath('//*[@id="ng-app"]/body/div/div[1]/div/table/tbody/tr[5]/td[2]/div[3]/div/table/tbody/tr[2]/td[2]/div[3]/div/table/tbody/tr[3]/td[2]/div[3]/div/table/tbody[1]/tr[1]/td[3]/button'))
projectDelete.click()
expect(projectDelete.isDisplayed()).toBe(true);
});
@@ -333,24 +333,24 @@ describe('testing the scenarios page for anonymous user', function () {
browser.get(baseURL+"#/scenarios/test-scenario");
var EC = browser.ExpectedConditions;
browser.wait(EC.urlContains(baseURL+ '#/scenarios/test-scenario'), 10000);
- var installersShow = element(by.xpath('//*[@id="ng-app"]/body/div/div[1]/div/table/tbody/tr[4]/td[2]/div[1]/a/p'))
+ var installersShow = element(by.xpath('//*[@id="ng-app"]/body/div/div[1]/div/table/tbody/tr[5]/td[2]/div[1]/a/p'))
installersShow.click();
- var installerShow = element(by.xpath('//*[@id="ng-app"]/body/div/div[1]/div/table/tbody/tr[4]/td[2]/div[3]/div/table/tbody/tr[1]/td[2]/a'))
+ var installerShow = element(by.xpath('//*[@id="ng-app"]/body/div/div[1]/div/table/tbody/tr[5]/td[2]/div[3]/div/table/tbody/tr[1]/td[2]/a'))
installerShow.click();
- var versionsShow = element(by.xpath('//*[@id="ng-app"]/body/div/div[1]/div/table/tbody/tr[4]/td[2]/div[3]/div/table/tbody/tr[2]/td[2]/div[1]/a/p'))
+ var versionsShow = element(by.xpath('//*[@id="ng-app"]/body/div/div[1]/div/table/tbody/tr[5]/td[2]/div[3]/div/table/tbody/tr[2]/td[2]/div[1]/a/p'))
versionsShow.click();
- var versionShow = element(by.xpath('//*[@id="ng-app"]/body/div/div[1]/div/table/tbody/tr[4]/td[2]/div[3]/div/table/tbody/tr[2]/td[2]/div[3]/div/table/tbody/tr[1]/td[2]/a'))
+ var versionShow = element(by.xpath('//*[@id="ng-app"]/body/div/div[1]/div/table/tbody/tr[5]/td[2]/div[3]/div/table/tbody/tr[2]/td[2]/div[3]/div/table/tbody/tr[1]/td[2]/a'))
versionShow.click()
- var projectsShow = element(by.xpath('//*[@id="ng-app"]/body/div/div[1]/div/table/tbody/tr[4]/td[2]/div[3]/div/table/tbody/tr[2]/td[2]/div[3]/div/table/tbody/tr[3]/td[2]/div[1]/a'))
+ var projectsShow = element(by.xpath('//*[@id="ng-app"]/body/div/div[1]/div/table/tbody/tr[5]/td[2]/div[3]/div/table/tbody/tr[2]/td[2]/div[3]/div/table/tbody/tr[3]/td[2]/div[1]/a'))
projectsShow.click();
- var projectShow = element(by.xpath('//*[@id="ng-app"]/body/div/div[1]/div/table/tbody/tr[4]/td[2]/div[3]/div/table/tbody/tr[2]/td[2]/div[3]/div/table/tbody/tr[3]/td[2]/div[3]/div/table/tbody/tr[1]/td[2]/a'))
+ var projectShow = element(by.xpath('//*[@id="ng-app"]/body/div/div[1]/div/table/tbody/tr[5]/td[2]/div[3]/div/table/tbody/tr[2]/td[2]/div[3]/div/table/tbody/tr[3]/td[2]/div[3]/div/table/tbody/tr[1]/td[2]/a'))
projectShow.click();
- var customsShow = element(by.xpath('//*[@id="ng-app"]/body/div/div[1]/div/table/tbody/tr[4]/td[2]/div[3]/div/table/tbody/tr[2]/td[2]/div[3]/div/table/tbody/tr[3]/td[2]/div[3]/div/table/tbody[1]/tr[4]/td[2]/a/p'))
+ var customsShow = element(by.xpath('//*[@id="ng-app"]/body/div/div[1]/div/table/tbody/tr[5]/td[2]/div[3]/div/table/tbody/tr[2]/td[2]/div[3]/div/table/tbody/tr[3]/td[2]/div[3]/div/table/tbody[1]/tr[4]/td[2]/a/p'))
customsShow.click();
var row = element.all(by.repeater('(indexCU, custom) in project.customs')).first();
var cells = row.all(by.tagName('td'));
expect(cells.get(0).getText()).toContain("dvs");
- var buttonAdd = element(by.xpath('//*[@id="ng-app"]/body/div/div[1]/div/table/tbody/tr[4]/td[2]/div[3]/div/table/tbody/tr[2]/td[2]/div[3]/div/table/tbody/tr[3]/td[2]/div[3]/div/table/tbody[1]/tr[4]/td[2]/button'))
+ var buttonAdd = element(by.xpath('//*[@id="ng-app"]/body/div/div[1]/div/table/tbody/tr[5]/td[2]/div[3]/div/table/tbody/tr[2]/td[2]/div[3]/div/table/tbody/tr[3]/td[2]/div[3]/div/table/tbody[1]/tr[4]/td[2]/button'))
buttonAdd.click()
expect(buttonAdd.isDisplayed()).toBe(true);
});
@@ -359,27 +359,182 @@ describe('testing the scenarios page for anonymous user', function () {
browser.get(baseURL+"#/scenarios/test-scenario");
var EC = browser.ExpectedConditions;
browser.wait(EC.urlContains(baseURL+ '#/scenarios/test-scenario'), 10000);
- var installersShow = element(by.xpath('//*[@id="ng-app"]/body/div/div[1]/div/table/tbody/tr[4]/td[2]/div[1]/a/p'))
+ var installersShow = element(by.xpath('//*[@id="ng-app"]/body/div/div[1]/div/table/tbody/tr[5]/td[2]/div[1]/a/p'))
installersShow.click();
- var installerShow = element(by.xpath('//*[@id="ng-app"]/body/div/div[1]/div/table/tbody/tr[4]/td[2]/div[3]/div/table/tbody/tr[1]/td[2]/a'))
+ var installerShow = element(by.xpath('//*[@id="ng-app"]/body/div/div[1]/div/table/tbody/tr[5]/td[2]/div[3]/div/table/tbody/tr[1]/td[2]/a'))
installerShow.click();
- var versionsShow = element(by.xpath('//*[@id="ng-app"]/body/div/div[1]/div/table/tbody/tr[4]/td[2]/div[3]/div/table/tbody/tr[2]/td[2]/div[1]/a/p'))
+ var versionsShow = element(by.xpath('//*[@id="ng-app"]/body/div/div[1]/div/table/tbody/tr[5]/td[2]/div[3]/div/table/tbody/tr[2]/td[2]/div[1]/a/p'))
versionsShow.click();
- var versionShow = element(by.xpath('//*[@id="ng-app"]/body/div/div[1]/div/table/tbody/tr[4]/td[2]/div[3]/div/table/tbody/tr[2]/td[2]/div[3]/div/table/tbody/tr[1]/td[2]/a'))
+ var versionShow = element(by.xpath('//*[@id="ng-app"]/body/div/div[1]/div/table/tbody/tr[5]/td[2]/div[3]/div/table/tbody/tr[2]/td[2]/div[3]/div/table/tbody/tr[1]/td[2]/a'))
versionShow.click()
- var projectsShow = element(by.xpath('//*[@id="ng-app"]/body/div/div[1]/div/table/tbody/tr[4]/td[2]/div[3]/div/table/tbody/tr[2]/td[2]/div[3]/div/table/tbody/tr[3]/td[2]/div[1]/a'))
+ var projectsShow = element(by.xpath('//*[@id="ng-app"]/body/div/div[1]/div/table/tbody/tr[5]/td[2]/div[3]/div/table/tbody/tr[2]/td[2]/div[3]/div/table/tbody/tr[3]/td[2]/div[1]/a'))
projectsShow.click();
- var projectShow = element(by.xpath('//*[@id="ng-app"]/body/div/div[1]/div/table/tbody/tr[4]/td[2]/div[3]/div/table/tbody/tr[2]/td[2]/div[3]/div/table/tbody/tr[3]/td[2]/div[3]/div/table/tbody/tr[1]/td[2]/a'))
+ var projectShow = element(by.xpath('//*[@id="ng-app"]/body/div/div[1]/div/table/tbody/tr[5]/td[2]/div[3]/div/table/tbody/tr[2]/td[2]/div[3]/div/table/tbody/tr[3]/td[2]/div[3]/div/table/tbody/tr[1]/td[2]/a'))
projectShow.click();
- var customsShow = element(by.xpath('//*[@id="ng-app"]/body/div/div[1]/div/table/tbody/tr[4]/td[2]/div[3]/div/table/tbody/tr[2]/td[2]/div[3]/div/table/tbody/tr[3]/td[2]/div[3]/div/table/tbody[1]/tr[4]/td[2]/a/p'))
+ var customsShow = element(by.xpath('//*[@id="ng-app"]/body/div/div[1]/div/table/tbody/tr[5]/td[2]/div[3]/div/table/tbody/tr[2]/td[2]/div[3]/div/table/tbody/tr[3]/td[2]/div[3]/div/table/tbody[1]/tr[4]/td[2]/a/p'))
customsShow.click();
var row = element.all(by.repeater('(indexCU, custom) in project.customs')).first();
var cells = row.all(by.tagName('td'));
expect(cells.get(0).getText()).toContain("dvs");
- var buttonDelete = element(by.xpath('//*[@id="ng-app"]/body/div/div[1]/div/table/tbody/tr[4]/td[2]/div[3]/div/table/tbody/tr[2]/td[2]/div[3]/div/table/tbody/tr[3]/td[2]/div[3]/div/table/tbody[1]/tr[4]/td[2]/table/tbody/tr[1]/td[2]/button'))
+ var buttonDelete = element(by.xpath('//*[@id="ng-app"]/body/div/div[1]/div/table/tbody/tr[5]/td[2]/div[3]/div/table/tbody/tr[2]/td[2]/div[3]/div/table/tbody/tr[3]/td[2]/div[3]/div/table/tbody[1]/tr[4]/td[2]/table/tbody/tr[1]/td[2]/button'))
buttonDelete.click()
expect(buttonDelete.isDisplayed()).toBe(true);
});
});
+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/deployResultsControllerSpec.js b/testapi/opnfv_testapi/tests/UI/e2e/deployResultsControllerSpec.js
index e00243b..40f60e4 100644
--- a/testapi/opnfv_testapi/tests/UI/e2e/deployResultsControllerSpec.js
+++ b/testapi/opnfv_testapi/tests/UI/e2e/deployResultsControllerSpec.js
@@ -383,7 +383,7 @@ describe('testing the result page for user', function () {
buttonClear.click();
var row = element.all(by.repeater('(index, result) in ctrl.data.deployresults')).first();
var cells = row.all(by.tagName('td'));
- expect(cells.get(0).getText()).toContain("3c9f8d62");
+ expect(cells.get(0).getText()).toContain("3c9f8d63");
});
it('view the deploy results ', function () {
diff --git a/testapi/opnfv_testapi/tests/UI/e2e/podsControllerSpec.js b/testapi/opnfv_testapi/tests/UI/e2e/podsControllerSpec.js
index 16b219d..ac1f954 100644
--- a/testapi/opnfv_testapi/tests/UI/e2e/podsControllerSpec.js
+++ b/testapi/opnfv_testapi/tests/UI/e2e/podsControllerSpec.js
@@ -78,7 +78,7 @@ describe('testing the Pods page for anonymous user', function () {
it('Sort the results by mode', function () {
browser.get(baseURL+'#/pods');
- var sortMode = element(by.xpath('//*[@id="ng-app"]/body/div/div[6]/div/table/thead/tr/th[4]/a[2]/span'))
+ var sortMode = element(by.xpath('//*[@id="ng-app"]/body/div/div[5]/div/table/thead/tr/th[4]/a[2]/span'))
sortMode.click();
var row = element.all(by.repeater('(index, pod) in ctrl.data.pods')).first();
var cells = row.all(by.tagName('td'));
@@ -87,7 +87,7 @@ describe('testing the Pods page for anonymous user', function () {
it('Sort the results by role', function () {
browser.get(baseURL+'#/pods');
- var sortRole = element(by.xpath('//*[@id="ng-app"]/body/div/div[6]/div/table/thead/tr/th[3]/a[2]/span'))
+ var sortRole = element(by.xpath('//*[@id="ng-app"]/body/div/div[5]/div/table/thead/tr/th[3]/a[2]/span'))
sortRole.click();
var row = element.all(by.repeater('(index, pod) in ctrl.data.pods')).first();
var cells = row.all(by.tagName('td'));
@@ -262,8 +262,11 @@ describe('testing the Pods page for authorized user', function () {
.isDisplayed()).toBe(true);
var buttonOK = element(by.buttonText('Ok'));
buttonOK.click();
- expect(element(by.cssContainingText(".alert","Delete Success"))
+ browser.ignoreSynchronization = true;
+ expect(element(by.cssContainingText(".success.show","Delete Success"))
.isDisplayed()).toBe(true);
+ browser.sleep(500);
+ browser.ignoreSynchronization = false;
});
it('Delete the pods ', function () {
@@ -272,8 +275,11 @@ describe('testing the Pods page for authorized user', function () {
deleteOperation.click();
var buttonOK = element(by.buttonText('Ok'));
buttonOK.click();
- expect(element(by.cssContainingText(".alert","Delete Success"))
+ browser.ignoreSynchronization = true;
+ expect(element(by.cssContainingText(".success.show","Delete Success"))
.isDisplayed()).toBe(true);
+ browser.sleep(500);
+ browser.ignoreSynchronization = false;
});
it('Create the pod', function () {
@@ -286,8 +292,11 @@ describe('testing the Pods page for authorized user', function () {
name.sendKeys('test1');
var buttonOK = element(by.buttonText('Ok'));
buttonOK.click();
- expect(element(by.cssContainingText(".alert","Create Success"))
+ browser.ignoreSynchronization = true;
+ expect(element(by.cssContainingText(".success.show","Create Success"))
.isDisplayed()).toBe(true);
+ browser.sleep(500);
+ browser.ignoreSynchronization = false;
});
it('Showing error when creating with a empty name ', function () {
@@ -299,8 +308,11 @@ describe('testing the Pods page for authorized user', function () {
browser.wait(EC.visibilityOf(name), 5000);
var buttonOK = element(by.buttonText('Ok'));
buttonOK.click()
- expect(element(by.cssContainingText(".alert","Name is missing."))
+ browser.ignoreSynchronization = true;
+ expect(element(by.cssContainingText(".error.show","Name is missing."))
.isDisplayed()).toBe(true);
+ browser.sleep(500);
+ browser.ignoreSynchronization = false;
});
it('cancel the delete confimation modal of the pod ', function () {
@@ -356,8 +368,11 @@ describe('testing the Pods page for authorized user', function () {
deleteOperation.click();
var buttonOK = element(by.buttonText('Ok'));
buttonOK.click();
- expect(element(by.css(".alert.alert-danger"))
+ browser.ignoreSynchronization = true;
+ expect(element(by.css(".error.show"))
.isDisplayed()).toBe(true);
+ browser.sleep(500);
+ browser.ignoreSynchronization = false;
});
it('view the test case ', function () {
@@ -394,8 +409,13 @@ describe('testing the Pods page for authorized user', function () {
},
]);
browser.get(baseURL+"#/pods");
- expect(element(by.css(".alert.alert-danger"))
+ var EC = browser.ExpectedConditions;
+ browser.wait(EC.urlContains(baseURL+ '/#/pods'), 5000);
+ browser.ignoreSynchronization = true;
+ expect(element(by.css(".error.show"))
.isDisplayed()).toBe(true);
+ browser.sleep(500);
+ browser.ignoreSynchronization = false;
});
}); \ No newline at end of file
diff --git a/testapi/opnfv_testapi/tests/UI/e2e/projectsControllerSpec.js b/testapi/opnfv_testapi/tests/UI/e2e/projectsControllerSpec.js
index ed5fe9f..da86389 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);
@@ -330,8 +324,12 @@ describe('testing the Project Link for user who is in submitter group', function
name.sendKeys('testproject');
var buttonOK = element(by.buttonText('Ok'));
buttonOK.click();
- expect(element(by.cssContainingText(".alert","Project is successfully created."))
+
+ browser.ignoreSynchronization = true;
+ expect(element(by.cssContainingText(".success.show","Project is successfully created."))
.isDisplayed()).toBe(true);
+ browser.sleep(500);
+ browser.ignoreSynchronization = false;
});
it('Show error if user doesnt have permission to Create the Project', function () {
@@ -346,7 +344,10 @@ describe('testing the Project Link for user who is in submitter group', function
description.sendKeys('demoDescription');
var buttonOK = element(by.buttonText('Ok'));
buttonOK.click();
- expect(element(by.css(".alert.alert-danger")).isDisplayed()).toBe(true);
+ browser.ignoreSynchronization = true;
+ expect(element(by.css(".error")).isDisplayed()).toBe(true);
+ browser.sleep(500);
+ browser.ignoreSynchronization = false;
});
it('Showing error when creating with a empty name ', function () {
@@ -358,8 +359,11 @@ describe('testing the Project Link for user who is in submitter group', function
browser.wait(EC.visibilityOf(name), 5000);
var buttonOK = element(by.buttonText('Ok'));
buttonOK.click();
+ browser.ignoreSynchronization = true;
expect(element(by.cssContainingText(".alert","Name is missing."))
.isDisplayed()).toBe(true);
+ browser.sleep(500);
+ browser.ignoreSynchronization = false;
});
it('Show error when user click the create button with an already existing name', function () {
@@ -374,7 +378,10 @@ describe('testing the Project Link for user who is in submitter group', function
description.sendKeys('demoDescription');
var buttonOK = element(by.buttonText('Ok'));
buttonOK.click();
- expect(element(by.css(".alert.alert-danger")).isDisplayed()).toBe(true);
+ browser.ignoreSynchronization = true;
+ expect(element(by.css(".error")).isDisplayed()).toBe(true);
+ browser.sleep(500);
+ browser.ignoreSynchronization = false;
});
it('cancel the delete confimation modal of the project ', function () {
@@ -394,8 +401,11 @@ describe('testing the Project Link for user who is in submitter group', function
.isDisplayed()).toBe(true);
var buttonOK = element(by.buttonText('Ok'));
buttonOK.click();
- expect(element(by.cssContainingText(".alert","Projects is successfully deleted"))
+ browser.ignoreSynchronization = true;
+ expect(element(by.cssContainingText(".success.show","Projects is successfully deleted"))
.isDisplayed()).toBe(true);
+ browser.sleep(500);
+ browser.ignoreSynchronization = false;
});
it(' Show error if user doesnt has permission to delete the projects ', function () {
@@ -448,7 +458,10 @@ describe('testing the Project Link for user who is in submitter group', function
deleteOperation.click();
var buttonOK = element(by.buttonText('Ok'));
buttonOK.click();
- expect(element(by.css(".alert.alert-danger")).isDisplayed()).toBe(true);
+ browser.ignoreSynchronization = true;
+ expect(element(by.css(".error")).isDisplayed()).toBe(true);
+ browser.sleep(500);
+ browser.ignoreSynchronization = false;
});
it('cancel the Edit modal of the Project ', function () {
@@ -474,8 +487,12 @@ describe('testing the Project Link for user who is in submitter group', function
name.sendKeys('test1');
var buttonOK = element(by.buttonText('Ok'));
buttonOK.click()
- expect(element(by.cssContainingText(".alert","Project is successfully updated."))
+ browser.ignoreSynchronization = true;
+ expect(element(by.cssContainingText(".success.show","Project is successfully updated."))
.isDisplayed()).toBe(true);
+ browser.sleep(500);
+ browser.ignoreSynchronization = false;
+
});
it('Show error if user doesnt has permission to edit the projects ', function () {
@@ -532,7 +549,10 @@ describe('testing the Project Link for user who is in submitter group', function
name.sendKeys('test1');
var buttonOK = element(by.buttonText('Ok'));
buttonOK.click()
- expect(element(by.css(".alert.alert-danger")).isDisplayed()).toBe(true);
+ browser.ignoreSynchronization = true;
+ expect(element(by.css(".error")).isDisplayed()).toBe(true);
+ browser.sleep(500);
+ browser.ignoreSynchronization = false;
});
it('Batch Delete the projects ', function () {
@@ -543,8 +563,12 @@ describe('testing the Project Link for user who is in submitter group', function
buttonDelete.click();
var buttonOK = element(by.buttonText('Ok'));
buttonOK.click();
- expect(element(by.cssContainingText(".alert","Projects is successfully deleted"))
+ browser.ignoreSynchronization = true;
+ expect(element(by.cssContainingText(".success.show","Projects is successfully deleted"))
.isDisplayed()).toBe(true);
+ browser.sleep(500);
+ browser.ignoreSynchronization = false;
+
});
it('If backend is not responding then show error when user click the create button',function(){
@@ -576,8 +600,10 @@ describe('testing the Project Link for user who is in submitter group', function
name.sendKeys('testproject');
details.sendKeys('demoDescription');
var buttonOK = element(by.buttonText('Ok'));
- buttonOK.click().then(function(){
- expect(element(by.css(".alert.alert-danger")).isDisplayed()).toBe(true);
- });
+ buttonOK.click()
+ browser.ignoreSynchronization = true;
+ expect(element(by.css(".error")).isDisplayed()).toBe(true);
+ browser.sleep(500);
+ browser.ignoreSynchronization = false;
});
})
diff --git a/testapi/opnfv_testapi/tests/UI/e2e/resultsControllerSpec.js b/testapi/opnfv_testapi/tests/UI/e2e/resultsControllerSpec.js
index d091a38..48690a1 100644
--- a/testapi/opnfv_testapi/tests/UI/e2e/resultsControllerSpec.js
+++ b/testapi/opnfv_testapi/tests/UI/e2e/resultsControllerSpec.js
@@ -44,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: {
@@ -65,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",
@@ -86,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: {
@@ -104,10 +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",
"public": "true",
- "version": "euphrates",
+ "version": "testversion",
"details": "",
"criteria": "PASS",
"_id": "5a45170bbb2092000e2643f6",
@@ -117,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"}
+ ]
+ }
+ }
+ }
]);
});
@@ -125,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);
});
@@ -137,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-2","failures")).isDisplayed()).toBe(true);
+ expect(element(by.cssContainingText(".leaf-value.col-md-10","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");
});
@@ -164,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'))
@@ -233,7 +291,7 @@ describe('testing the result page for user', function () {
method: 'GET',
queryString: {
page: '1',
- project: 'testproject'
+ installer: 'testinstaller'
}
},
response: {
@@ -250,7 +308,7 @@ describe('testing the result page for user', function () {
"case_name": "testcase",
"build_tag": null,
"user": null,
- "installer": "fuel",
+ "installer": "testinstaller",
"scenario": "test-scenario",
"public": "true",
"version": "euphrates",
@@ -270,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: {
@@ -288,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",
@@ -302,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"}
+ ]
+ }
+ }
+ }
]);
});
@@ -333,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");
});
@@ -350,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();
@@ -367,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/scenarioControllerSpec.js b/testapi/opnfv_testapi/tests/UI/e2e/scenarioControllerSpec.js
index 7777721..37b42dc 100644
--- a/testapi/opnfv_testapi/tests/UI/e2e/scenarioControllerSpec.js
+++ b/testapi/opnfv_testapi/tests/UI/e2e/scenarioControllerSpec.js
@@ -682,8 +682,11 @@ describe('testing the scenarios page for user', function () {
name.sendKeys('test');
var buttonOk = element(by.xpath('//*[@id="ng-app"]/body/div[3]/div/div/div/div[2]/button[1]'))
buttonOk.click()
- expect(element(by.cssContainingText(".alert","Installers are successfully updated."))
+ browser.ignoreSynchronization = true;
+ expect(element(by.cssContainingText(".success.show","Installers are successfully updated."))
.isDisplayed()).toBe(true);
+ browser.sleep(500);
+ browser.ignoreSynchronization = false;
});
@@ -720,8 +723,11 @@ describe('testing the scenarios page for user', function () {
.isDisplayed()).toBe(true);
var buttonOK = element(by.buttonText('Ok'));
buttonOK.click();
- expect(element(by.cssContainingText(".alert","Installer is successfully deleted."))
+ browser.ignoreSynchronization = true;
+ expect(element(by.cssContainingText(".success.show","Installer is successfully deleted."))
.isDisplayed()).toBe(true);
+ browser.sleep(500);
+ browser.ignoreSynchronization = false;
});
it( 'Expand installer by user', function() {
@@ -753,8 +759,11 @@ describe('testing the scenarios page for user', function () {
owner.sendKeys('testOwner');
var buttonOk = element(by.xpath('//*[@id="ng-app"]/body/div[3]/div/div/div/div[2]/button[1]'))
buttonOk.click()
- expect(element(by.cssContainingText(".alert","Versions are successfully updated."))
+ browser.ignoreSynchronization = true;
+ expect(element(by.cssContainingText(".success.show","Versions are successfully updated."))
.isDisplayed()).toBe(true);
+ browser.sleep(500);
+ browser.ignoreSynchronization = false;
});
it( 'Expand versions by user', function() {
@@ -793,8 +802,11 @@ describe('testing the scenarios page for user', function () {
.isDisplayed()).toBe(true);
var buttonOK = element(by.buttonText('Ok'));
buttonOK.click();
- expect(element(by.cssContainingText(".alert","Versions are successfully deleted."))
+ browser.ignoreSynchronization = true;
+ expect(element(by.cssContainingText(".success.show","Versions are successfully deleted."))
.isDisplayed()).toBe(true);
+ browser.sleep(500);
+ browser.ignoreSynchronization = false;
});
it( 'Expand version by user', function() {
@@ -832,8 +844,11 @@ describe('testing the scenarios page for user', function () {
project.sendKeys('testP');
var buttonOk = element(by.xpath('//*[@id="ng-app"]/body/div[3]/div/div/div/div[2]/button[1]'))
buttonOk.click()
- expect(element(by.cssContainingText(".alert","Projects are successfully updated."))
+ browser.ignoreSynchronization = true;
+ expect(element(by.cssContainingText(".success.show","Projects are successfully updated."))
.isDisplayed()).toBe(true);
+ browser.sleep(500);
+ browser.ignoreSynchronization = false;
});
it( 'Expand projects by user', function() {
@@ -878,8 +893,11 @@ describe('testing the scenarios page for user', function () {
.isDisplayed()).toBe(true);
var buttonOK = element(by.buttonText('Ok'));
buttonOK.click();
- expect(element(by.cssContainingText(".alert","Projects are successfully Deleted."))
+ browser.ignoreSynchronization = true;
+ expect(element(by.cssContainingText(".success.show","Projects are successfully Deleted."))
.isDisplayed()).toBe(true);
+ browser.sleep(500);
+ browser.ignoreSynchronization = false;
});
it( 'Expand project by user', function() {
@@ -1011,8 +1029,11 @@ describe('testing the scenarios page for user', function () {
custom.sendKeys('testC');
var buttonOk = element(by.xpath('//*[@id="ng-app"]/body/div[3]/div/div/div/div[2]/button[1]'))
buttonOk.click()
- expect(element(by.cssContainingText(".alert","Customs are successfully updated."))
+ browser.ignoreSynchronization = true;
+ expect(element(by.cssContainingText(".success.show","Customs are successfully updated."))
.isDisplayed()).toBe(true);
+ browser.sleep(500);
+ browser.ignoreSynchronization = false;
});
it( 'Add multiple Customs by user', function() {
@@ -1043,8 +1064,11 @@ describe('testing the scenarios page for user', function () {
custom.sendKeys('testC,testD,');
var buttonOk = element(by.xpath('//*[@id="ng-app"]/body/div[3]/div/div/div/div[2]/button[1]'))
buttonOk.click()
- expect(element(by.cssContainingText(".alert","Customs are successfully updated."))
+ browser.ignoreSynchronization = true;
+ expect(element(by.cssContainingText(".success.show","Customs are successfully updated."))
.isDisplayed()).toBe(true);
+ browser.sleep(500);
+ browser.ignoreSynchronization = false;
});
it( 'Delete Customs by user', function() {
@@ -1074,8 +1098,11 @@ describe('testing the scenarios page for user', function () {
.isDisplayed()).toBe(true);
var buttonOk = element(by.xpath('//*[@id="ng-app"]/body/div[3]/div/div/div[3]/button[1]'))
buttonOk.click()
- expect(element(by.cssContainingText(".alert","Customs are successfully deleted."))
+ browser.ignoreSynchronization = true;
+ expect(element(by.cssContainingText(".success.show","Customs are successfully deleted."))
.isDisplayed()).toBe(true);
+ browser.sleep(500);
+ browser.ignoreSynchronization = false;
});
}); \ No newline at end of file
diff --git a/testapi/opnfv_testapi/tests/UI/e2e/scenariosControllerSpec.js b/testapi/opnfv_testapi/tests/UI/e2e/scenariosControllerSpec.js
index bed80dd..55922ad 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[5]/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);
@@ -535,8 +284,11 @@ describe('testing the scenarios page for user', function () {
name.sendKeys('test');
var buttonOK = element(by.buttonText('Ok'));
buttonOK.click();
- expect(element(by.cssContainingText(".alert","Scenario is successfully created."))
+ browser.ignoreSynchronization = true;
+ expect(element(by.cssContainingText(".success.show","Scenario is successfully created."))
.isDisplayed()).toBe(true);
+ browser.sleep(500);
+ browser.ignoreSynchronization = false;
});
it('create scenarrio by user with installers ', function () {
@@ -555,8 +307,11 @@ describe('testing the scenarios page for user', function () {
buttonOK.click();
var buttonOK = element(by.buttonText('Ok'));
buttonOK.click();
- expect(element(by.cssContainingText(".alert","Scenario is successfully created."))
+ browser.ignoreSynchronization = true;
+ expect(element(by.cssContainingText(".success.show","Scenario is successfully created."))
.isDisplayed()).toBe(true);
+ browser.sleep(500);
+ browser.ignoreSynchronization = false;
});
it('create scenarrio by user with installers with versions ', function () {
@@ -584,8 +339,11 @@ describe('testing the scenarios page for user', function () {
buttonOK.click();
var buttonOK = element(by.buttonText('Ok'));
buttonOK.click();
- expect(element(by.cssContainingText(".alert","Scenario is successfully created."))
+ browser.ignoreSynchronization = true;
+ expect(element(by.cssContainingText(".success.show","Scenario is successfully created."))
.isDisplayed()).toBe(true);
+ browser.sleep(500);
+ browser.ignoreSynchronization = false;
});
it('create scenarrio by user with installers with versions with project', function () {
@@ -620,8 +378,11 @@ describe('testing the scenarios page for user', function () {
buttonOK.click();
var buttonOK = element(by.buttonText('Ok'));
buttonOK.click();
- expect(element(by.cssContainingText(".alert","Scenario is successfully created."))
+ browser.ignoreSynchronization = true;
+ expect(element(by.cssContainingText(".success.show","Scenario is successfully created."))
.isDisplayed()).toBe(true);
+ browser.sleep(500);
+ browser.ignoreSynchronization = false;
});
it('create scenarrio by user with installers with versions with project with custom', function () {
@@ -663,8 +424,11 @@ describe('testing the scenarios page for user', function () {
buttonOK.click();
var buttonOK = element(by.buttonText('Ok'));
buttonOK.click();
- expect(element(by.cssContainingText(".alert","Scenario is successfully created."))
+ browser.ignoreSynchronization = true;
+ expect(element(by.cssContainingText(".success.show","Scenario is successfully created."))
.isDisplayed()).toBe(true);
+ browser.sleep(500);
+ browser.ignoreSynchronization = false;
});
it('view scenarrio by user ', function () {
@@ -694,8 +458,11 @@ describe('testing the scenarios page for user', function () {
.isDisplayed()).toBe(true);
var buttonOK = element(by.buttonText('Ok'));
buttonOK.click();
- expect(element(by.cssContainingText(".alert","Scenario is successfully deleted."))
+ browser.ignoreSynchronization = true;
+ expect(element(by.cssContainingText(".success.show","Scenario is successfully deleted."))
.isDisplayed()).toBe(true);
+ browser.sleep(500);
+ browser.ignoreSynchronization = false;
});
it('Batch Delete the scenarios ', function () {
@@ -706,8 +473,11 @@ describe('testing the scenarios page for user', function () {
buttonDelete.click();
var buttonOK = element(by.buttonText('Ok'));
buttonOK.click();
- expect(element(by.cssContainingText(".alert","Scenario is successfully deleted."))
+ browser.ignoreSynchronization = true;
+ expect(element(by.cssContainingText(".success.show","Scenario is successfully deleted."))
.isDisplayed()).toBe(true);
+ browser.sleep(500);
+ browser.ignoreSynchronization = false;
});
it('Edit the scenarios ', function () {
@@ -720,8 +490,11 @@ describe('testing the scenarios page for user', function () {
name.sendKeys('test2');
var buttonOK = element(by.buttonText('Ok'));
buttonOK.click()
- expect(element(by.cssContainingText(".alert","Scenario is successfully Updated."))
+ browser.ignoreSynchronization = true;
+ expect(element(by.cssContainingText(".success.show","Scenario is successfully Updated."))
.isDisplayed()).toBe(true);
+ browser.sleep(500);
+ browser.ignoreSynchronization = false;
});
}); \ No newline at end of file
diff --git a/testapi/opnfv_testapi/tests/UI/e2e/testCasesControllerSpec.js b/testapi/opnfv_testapi/tests/UI/e2e/testCasesControllerSpec.js
index 53e7bdf..38e0f24 100644
--- a/testapi/opnfv_testapi/tests/UI/e2e/testCasesControllerSpec.js
+++ b/testapi/opnfv_testapi/tests/UI/e2e/testCasesControllerSpec.js
@@ -550,8 +550,11 @@ describe('testing the test cases page for user who is in submitter group', funct
name.sendKeys('test');
var buttonOK = element(by.buttonText('Ok'));
buttonOK.click();
- expect(element(by.cssContainingText(".alert","Testcase is successfully created."))
+ browser.ignoreSynchronization = true;
+ expect(element(by.cssContainingText(".success.show","Testcase is successfully created."))
.isDisplayed()).toBe(true);
+ browser.sleep(500);
+ browser.ignoreSynchronization = false;
});
it('Showing error when creating with a empty name ', function () {
@@ -565,8 +568,11 @@ describe('testing the test cases page for user who is in submitter group', funct
browser.wait(EC.visibilityOf(name), 5000);
var buttonOK = element(by.buttonText('Ok'));
buttonOK.click();
- expect(element(by.cssContainingText(".alert","Name is missing."))
+ browser.ignoreSynchronization = true;
+ expect(element(by.cssContainingText(".error.show","Name is missing."))
.isDisplayed()).toBe(true);
+ browser.sleep(500);
+ browser.ignoreSynchronization = false;
});
it('cancel the delete confimation modal of the test case ', function () {
@@ -590,8 +596,11 @@ describe('testing the test cases page for user who is in submitter group', funct
deleteOperation.click();
var buttonOK = element(by.buttonText('Ok'));
buttonOK.click();
- expect(element(by.cssContainingText(".alert","Test case is successfully deleted"))
+ browser.ignoreSynchronization = true;
+ expect(element(by.cssContainingText(".success.show","Test case is successfully deleted"))
.isDisplayed()).toBe(true);
+ browser.sleep(500);
+ browser.ignoreSynchronization = false;
});
it('cancel the Edit modal of the test case ', function () {
@@ -621,8 +630,11 @@ describe('testing the test cases page for user who is in submitter group', funct
name.sendKeys('test1');
var buttonOK = element(by.buttonText('Ok'));
buttonOK.click();
- expect(element(by.cssContainingText(".alert","Test case is successfully updated"))
+ browser.ignoreSynchronization = true;
+ expect(element(by.cssContainingText(".success.show","Test case is successfully updated"))
.isDisplayed()).toBe(true);
+ browser.sleep(500);
+ browser.ignoreSynchronization = false;
});
it('view the test case ', function () {
@@ -646,7 +658,10 @@ describe('testing the test cases page for user who is in submitter group', funct
buttonDelete.click();
var buttonOK = element(by.buttonText('Ok'));
buttonOK.click();
- expect(element(by.cssContainingText(".alert","Test case is successfully deleted"))
+ browser.ignoreSynchronization = true;
+ expect(element(by.cssContainingText(".success.show","Test case is successfully deleted"))
.isDisplayed()).toBe(true);
+ browser.sleep(500);
+ browser.ignoreSynchronization = false;
});
})
diff --git a/testapi/opnfv_testapi/tests/unit/executor.py b/testapi/opnfv_testapi/tests/unit/executor.py
index d08782c..7c8cb8a 100644
--- a/testapi/opnfv_testapi/tests/unit/executor.py
+++ b/testapi/opnfv_testapi/tests/unit/executor.py
@@ -18,9 +18,9 @@ O_get_secure_cookie = (
def thread_execute(method, *args, **kwargs):
- with ThreadPoolExecutor(max_workers=2) as executor:
- result = executor.submit(method, *args, **kwargs)
- return result
+ with ThreadPoolExecutor(max_workers=2) as executor:
+ result = executor.submit(method, *args, **kwargs)
+ return result
def mock_invalid_lfid():
@@ -91,7 +91,7 @@ def delete(excepted_status, excepted_response):
def wrap(self):
request = delete_request(self)
if isinstance(request, tuple):
- status, body = self.delete(request[0], *(request[1]))
+ status, body = self.delete(*request)
else:
status, body = self.delete(request)
if excepted_status == httplib.OK:
diff --git a/testapi/opnfv_testapi/tests/unit/fake_pymongo.py b/testapi/opnfv_testapi/tests/unit/fake_pymongo.py
index 041e6e8..631e9ac 100644
--- a/testapi/opnfv_testapi/tests/unit/fake_pymongo.py
+++ b/testapi/opnfv_testapi/tests/unit/fake_pymongo.py
@@ -15,9 +15,9 @@ from concurrent.futures import ThreadPoolExecutor
def thread_execute(method, *args, **kwargs):
- with ThreadPoolExecutor(max_workers=2) as executor:
- result = executor.submit(method, *args, **kwargs)
- return result
+ with ThreadPoolExecutor(max_workers=2) as executor:
+ result = executor.submit(method, *args, **kwargs)
+ return result
class MemCursor(object):
diff --git a/testapi/opnfv_testapi/tests/unit/handlers/test_base.py b/testapi/opnfv_testapi/tests/unit/handlers/test_base.py
index 9a7bc5c..1fd3324 100644
--- a/testapi/opnfv_testapi/tests/unit/handlers/test_base.py
+++ b/testapi/opnfv_testapi/tests/unit/handlers/test_base.py
@@ -63,7 +63,8 @@ class TestBase(testing.AsyncHTTPTestCase):
'opnfv-gerrit-functest-submitters',
'opnfv-gerrit-qtip-submitters',
'opnfv-gerrit-qtip-contributors',
- 'opnfv-gerrit-apex-submitters']
+ 'opnfv-gerrit-apex-submitters',
+ 'opnfv-gerrit-noProject-submitters']
})
def tearDown(self):
@@ -158,7 +159,6 @@ class TestBase(testing.AsyncHTTPTestCase):
res = self.fetch(url,
method='DELETE',
headers=self.headers)
-
return res.code, res.body
def delete(self, *args):
diff --git a/testapi/opnfv_testapi/tests/unit/handlers/test_testcase.py b/testapi/opnfv_testapi/tests/unit/handlers/test_testcase.py
index 97325e2..e0ce381 100644
--- a/testapi/opnfv_testapi/tests/unit/handlers/test_testcase.py
+++ b/testapi/opnfv_testapi/tests/unit/handlers/test_testcase.py
@@ -32,7 +32,6 @@ class TestCaseBase(base.TestBase):
self.update_res = tcm.Testcase
self.basePath = '/api/v1/projects/%s/cases'
fake_pymongo.projects.insert(self.project_e.format())
- print self.req_d.format()
self.results_d = rm.ResultCreateRequest.from_dict(
self.load_json('test_result'))
@@ -72,8 +71,8 @@ class TestCaseBase(base.TestBase):
return super(TestCaseBase, self).update(new, self.project, case)
@executor.mock_valid_lfid()
- def delete(self, case):
- return super(TestCaseBase, self).delete(self.project, case)
+ def delete(self, case=None, project=None):
+ return super(TestCaseBase, self).delete(project, case)
class TestCaseCreate(TestCaseBase):
@@ -81,6 +80,11 @@ class TestCaseCreate(TestCaseBase):
def test_noBody(self):
return None
+ @executor.create(httplib.FORBIDDEN, message.no_permission())
+ def test_unauthorized(self):
+ self.project = 'newProject'
+ return self.req_d
+
@executor.create(httplib.FORBIDDEN, message.not_found_base)
def test_noProject(self):
self.project = 'noProject'
@@ -154,6 +158,12 @@ class TestCaseUpdate(TestCaseBase):
self.create_e()
return self.update_req, self.req_d.name
+ @executor.update(httplib.FORBIDDEN, message.no_permission())
+ def test_unauthorized(self):
+ update_req_e = tcm.TestcaseUpdateRequest(project_name="newProject",
+ **self.req_e.format())
+ return update_req_e, self.req_d.name
+
@executor.update(httplib.FORBIDDEN, message.no_update())
def test_noUpdate(self):
update = tcm.TestcaseUpdateRequest(project_name=self.project,
@@ -184,19 +194,26 @@ class TestCaseDelete(TestCaseBase):
fake_pymongo.testcases.insert({
'name': self.results_d.case_name,
'project_name': self.results_d.project_name})
+ fake_pymongo.testcases.insert({
+ 'name': 'newCase',
+ 'project_name': 'newProject'})
@executor.delete(httplib.NOT_FOUND, message.not_found_base)
def test_notFound(self):
- return 'notFound'
+ return 'notFound', self.project
+
+ @executor.delete(httplib.FORBIDDEN, message.no_permission())
+ def test_unauthorized(self):
+ return 'newCase', 'newProject'
@executor.delete(httplib.UNAUTHORIZED, message.tied_with_resource())
def test_deleteNotAllowed(self):
- print self.create_help('/api/v1/results', self.results_d)
- return self.results_d.case_name
+ self.create_help('/api/v1/results', self.results_d)
+ return self.results_d.case_name, self.project
@executor.delete(httplib.OK, '_delete_success')
def test_success(self):
- return self.req_d.name
+ return self.req_d.name, self.project
def _delete_success(self, body):
self.assertEqual(body, '')
diff --git a/testapi/opnfv_testapi/ui/Gruntfile.js b/testapi/opnfv_testapi/ui/Gruntfile.js
index 805ad9f..d6a2f47 100644
--- a/testapi/opnfv_testapi/ui/Gruntfile.js
+++ b/testapi/opnfv_testapi/ui/Gruntfile.js
@@ -6,7 +6,22 @@ module.exports = function (grunt) {
grunt.loadNpmTasks('grunt-wait');
grunt.loadNpmTasks('grunt-contrib-copy');
grunt.loadNpmTasks('grunt-contrib-connect');
+ grunt.loadNpmTasks('grunt-convert');
grunt.initConfig({
+ convert: {
+ options: {
+ explicitArray: false,
+ },
+ json2xml: {
+ options: {
+ xml: {
+ header: true
+ }
+ },
+ src: ['../tests/UI/coverage/coverage.json'],
+ dest: '../tests/UI/coverage/coverage.xml'
+ }
+ },
connect: {
server: {
options: {
@@ -137,6 +152,7 @@ module.exports = function (grunt) {
makeReport: {
src: '../tests/UI/coverage/*.json',
options: {
+ type: 'cobertura',
print: 'detail'
}
}
@@ -159,6 +175,7 @@ module.exports = function (grunt) {
'wait:default',
'protractor_coverage',
'makeReport',
+ 'convert',
'shell:deleteFiles'
]);
}
diff --git a/testapi/opnfv_testapi/ui/app.js b/testapi/opnfv_testapi/ui/app.js
index ada7577..3fb4bc7 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
@@ -64,6 +64,21 @@
angular
.module('testapiApp')
+ .service('dataFieldService', function(){
+ this.dataFunction = dataFunction
+ function dataFunction(data, data_field){
+ Object.keys(data).forEach(function (key) {
+ if (typeof data[key] === 'object' && data[key] != null) {
+ return dataFunction(data[key], data_field);
+ }
+ data_field[key] = key.replace(/_/g, " ").trim();
+ });
+ return data_field;
+ }
+ });
+
+ angular
+ .module('testapiApp')
.directive('dynamicModel', ['$compile', '$parse', function ($compile, $parse) {
return {
restrict: 'A',
diff --git a/testapi/opnfv_testapi/ui/components/deploy-results/deploy-result/deployResult.html b/testapi/opnfv_testapi/ui/components/deploy-results/deploy-result/deployResult.html
index 82a0780..c0803ff 100644
--- a/testapi/opnfv_testapi/ui/components/deploy-results/deploy-result/deployResult.html
+++ b/testapi/opnfv_testapi/ui/components/deploy-results/deploy-result/deployResult.html
@@ -3,72 +3,16 @@
<div class="table-responsive">
<table class="table" ng-data="ctrl.data.pods">
<tbody>
- <tr style="padding:9px">
- <td class="podsTableTd">Id&nbsp;:</td>
- <td class="podsTableLeftTd">{{ctrl.data._id}}</td>
- </tr>
- <tr style="padding:9px">
- <td class="podsTableTd">Installer&nbsp;:</td>
- <td width="90%" class="podsTableLeftTd">{{ctrl.data.installer}}</td>
- </tr>
- <tr style="padding:9px">
- <td class="podsTableTd">Version&nbsp;:</td>
- <td width="90%" class="podsTableLeftTd">{{ctrl.data.version}}</td>
- </tr>
- <tr style="padding:9px">
- <td class="podsTableTd">Scenario&nbsp;:</td>
- <td width="90%" class="podsTableLeftTd">{{ctrl.data.scenario}}</td>
- </tr>
- <tr style="padding:9px">
- <td class="podsTableTd">Pod&nbsp;Name&nbsp;:</td>
- <td width="90%" class="podsTableLeftTd">{{ctrl.data.pod_name}}</td>
- </tr>
- <tr style="padding:9px">
- <td class="podsTableTd">Criteria&nbsp;:</td>
- <td width="90%" class="podsTableLeftTd">{{ctrl.data.criteria}}</td>
+ <tr ng-repeat-start="(index, detail) in ctrl.data_field" style="padding:9px">
+ <td class="podsTableTd">{{detail | capitalize}}&nbsp;:</td>
+ <td width="86%" class="podsTableLeftTd">{{ctrl.data[index]}}</td>
</tr>
- <tr style="padding:9px">
- <td class="podsTableTd">Start&nbsp;Date&nbsp;:</td>
- <td width="90%" class="podsTableLeftTd">{{ctrl.data.start_date}}</td>
- </tr>
- <tr style="padding:9px">
- <td class="podsTableTd">Stop&nbsp;Date&nbsp;:</td>
- <td width="90%" class="podsTableLeftTd">{{ctrl.data.stop_date}}</td>
- </tr>
- <tr style="padding:9px">
- <td class="podsTableTd">Job&nbsp;Name&nbsp;:</td>
- <td width="90%" class="podsTableLeftTd">{{ctrl.data.job_name}}</td>
- </tr>
- <tr style="padding:9px">
- <td class="podsTableTd">Build&nbsp;ID&nbsp;:</td>
- <td width="90%" class="podsTableLeftTd">{{ctrl.data['build_id']}}</td>
- </tr>
- <tr style="padding:9px">
- <td class="podsTableTd">Upstream&nbsp;Job&nbsp;Name&nbsp;:</td>
- <td width="90%" class="podsTableLeftTd">{{ctrl.data.upstream_job_name}}</td>
- </tr>
- <tr style="padding:9px">
- <td class="podsTableTd">Upstream&nbspBuild&nbsp;ID&nbsp;:</td>
- <td width="90%" class="podsTableLeftTd">{{ctrl.data.upstream_build_id}}</td>
+ <tr ng-repeat-end=>
</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 ng-repeat-start="(index, detail) in ctrl.data.details" style="padding:9px">
- <td class="podsTableTd">{{index | capitalize}}&nbsp;:</td>
- <td width="90%" class="podsTableLeftTd">{{detail}}</td>
- </tr>
- <tr ng-repeat-end=>
- </tr>
- </tbody>
- </table>
+ <td width="86%" class="podsTableLeftTd">
+ <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/deploy-results/deploy-result/deployResultController.js b/testapi/opnfv_testapi/ui/components/deploy-results/deploy-result/deployResultController.js
index 40cf1cb..6f9b84c 100644
--- a/testapi/opnfv_testapi/ui/components/deploy-results/deploy-result/deployResultController.js
+++ b/testapi/opnfv_testapi/ui/components/deploy-results/deploy-result/deployResultController.js
@@ -21,7 +21,7 @@
DeployResultController.$inject = [
'$scope', '$http', '$filter', '$state', '$window', '$uibModal', 'testapiApiUrl','raiseAlert',
- 'confirmModal'
+ 'confirmModal', 'dataFieldService'
];
/**
@@ -30,12 +30,16 @@
* through result declared in TestAPI.
*/
function DeployResultController($scope, $http, $filter, $state, $window, $uibModal, testapiApiUrl,
- raiseAlert, confirmModal) {
+ raiseAlert, confirmModal, dataFieldService) {
var ctrl = this;
ctrl.url = testapiApiUrl + '/deployresults';
ctrl._id = $state.params['_id'];
ctrl.loadDetails = loadDetails
- ctrl.showDetails = showDetails
+ ctrl.data_field = {}
+
+ ctrl.json = {};
+ ctrl.json.string = '{"id": ""}';
+ ctrl.json.object = JSON.parse(ctrl.json.string);
/**
*Contact the testapi and retrevie the result details
@@ -46,6 +50,10 @@
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)
+ delete ctrl.data.details;
+ ctrl.data_field = dataFieldService.dataFunction(ctrl.data, ctrl.data_field)
}).catch(function (error) {
ctrl.data = null;
ctrl.showError = true;
@@ -53,13 +61,6 @@
});
}
- 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/pods/pod/pod.html b/testapi/opnfv_testapi/ui/components/pods/pod/pod.html
index 6aace92..f9ab7c1 100644
--- a/testapi/opnfv_testapi/ui/components/pods/pod/pod.html
+++ b/testapi/opnfv_testapi/ui/components/pods/pod/pod.html
@@ -3,33 +3,11 @@
<div class="table-responsive">
<table class="table" ng-data="ctrl.data.pods">
<tbody>
- <tr style="padding:9px">
- <td class="podsTableTd">Id&nbsp;:</td>
- <td class="podsTableLeftTd">{{ctrl.data._id}}</td>
+ <tr ng-repeat-start="(index, detail) in ctrl.data_field" style="padding:9px">
+ <td class="podsTableTd">{{detail | capitalize}}&nbsp;:</td>
+ <td width="90%" class="podsTableLeftTd">{{ctrl.data[index]}}</td>
</tr>
- <tr style="padding:9px">
- <td class="podsTableTd">Name&nbsp;:</td>
- <td width="90%" class="podsTableLeftTd">{{ctrl.data.name}}</td>
- </tr>
- <tr style="padding:9px">
- <td class="podsTableTd">Creator&nbsp;:</td>
- <td width="90%" class="podsTableLeftTd">{{ctrl.data.creator}}</td>
- </tr>
- <tr style="padding:9px">
- <td class="podsTableTd">Role&nbsp;:</td>
- <td width="90%" class="podsTableLeftTd">{{ctrl.data.role}}</td>
- </tr>
- <tr style="padding:9px">
- <td class="podsTableTd">Mode&nbsp;:</td>
- <td width="90%" class="podsTableLeftTd">{{ctrl.data.mode}}</td>
- </tr>
- <tr style="padding:9px">
- <td class="podsTableTd">Created&nbsp;at&nbsp;:</td>
- <td width="90%" class="podsTableLeftTd">{{ctrl.data['creation_date']}}</td>
- </tr>
- <tr style="padding:9px">
- <td class="podsTableTd">Details&nbsp;:</td>
- <td width="90%" class="podsTableLeftTd">{{ctrl.data.details}}</td>
+ <tr ng-repeat-end=>
</tr>
</tbody>
</table>
diff --git a/testapi/opnfv_testapi/ui/components/pods/pod/podController.js b/testapi/opnfv_testapi/ui/components/pods/pod/podController.js
index a2e18e8..39ba599 100644
--- a/testapi/opnfv_testapi/ui/components/pods/pod/podController.js
+++ b/testapi/opnfv_testapi/ui/components/pods/pod/podController.js
@@ -21,7 +21,7 @@
PodController.$inject = [
'$scope', '$http', '$filter', '$state', '$window', '$uibModal', 'testapiApiUrl','raiseAlert',
- 'confirmModal'
+ 'confirmModal', 'dataFieldService'
];
/**
@@ -30,11 +30,12 @@
* through pod declared in TestAPI.
*/
function PodController($scope, $http, $filter, $state, $window, $uibModal, testapiApiUrl,
- raiseAlert, confirmModal) {
+ raiseAlert, confirmModal, dataFieldService) {
var ctrl = this;
ctrl.url = testapiApiUrl + '/pods';
ctrl.name = $state.params['name'];
- ctrl.loadDetails = loadDetails
+ ctrl.loadDetails = loadDetails;
+ ctrl.data_field = {};
/**
*Contact the testapi and retrevie the pod details
@@ -45,6 +46,7 @@
ctrl.podsRequest =
$http.get(podUrl).success(function (data) {
ctrl.data = data;
+ ctrl.data_field = dataFieldService.dataFunction(ctrl.data, ctrl.data_field)
}).catch(function (error) {
ctrl.data = null;
ctrl.showError = true;
diff --git a/testapi/opnfv_testapi/ui/components/pods/pods.html b/testapi/opnfv_testapi/ui/components/pods/pods.html
index 8e66a9c..b5dadf5 100644
--- a/testapi/opnfv_testapi/ui/components/pods/pods.html
+++ b/testapi/opnfv_testapi/ui/components/pods/pods.html
@@ -19,22 +19,18 @@
<div class="col-sm-1 pull-right">
<button type="button" class="btn btn-success" ng-click="ctrl.listPods()">
<i class="fa fa-search"></i> Filter</button>
+ <div ng-class="{'show': ctrl.showError}" id="toast" class="error">
+ <span class="glyphicon glyphicon-exclamation-sign" aria-hidden="true" ></span>
+ {{ctrl.error}}</div>
+ <div ng-class="{'show': ctrl.showSuccess}" id="toast" class="success">
+ <span class="glyphicon glyphicon-ok" aria-hidden="true"></span>
+ {{ctrl.success}}</div>
</div>
<div class="col-sm-3 pull-right">
<span style="margin-top:6px">Search:&nbsp;&nbsp;</span>
<input type="text" class="form-control search" ng-enter="ctrl.listPods()" ng-Model="ctrl.filterText" placeholder="Search String">
</div>
</div>
-<div class="col-md-12">
- <div ng-show="ctrl.showError" class="col-md-12 alert alert-danger" role="alert">
- <span class="pull-right">&nbsp;{{ctrl.error}}</span>
- <span class="glyphicon glyphicon-exclamation-sign pull-right" aria-hidden="true" >Error:</span>
- </div>
- <div ng-show="ctrl.showSuccess" class="col-md-12 alert alert-success" role="alert">
- <span class="pull-right">&nbsp;{{ctrl.success}}</span>
- <span class="glyphicon glyphicon-ok pull-right" aria-hidden="true"></span>
- </div>
-</div>
<div class="col-md-12" style="padding-right:0px">
<div class="table-responsive">
<table class="table table-bordered table-hover" ng-data="ctrl.data.pods">
diff --git a/testapi/opnfv_testapi/ui/components/pods/podsController.js b/testapi/opnfv_testapi/ui/components/pods/podsController.js
index f405ecb..3b6ab97 100644
--- a/testapi/opnfv_testapi/ui/components/pods/podsController.js
+++ b/testapi/opnfv_testapi/ui/components/pods/podsController.js
@@ -21,7 +21,7 @@
PodsController.$inject = [
'$scope', '$http', '$filter', '$state', '$window', '$uibModal', 'testapiApiUrl','raiseAlert',
- 'confirmModal', 'keepState', 'sortService'
+ 'confirmModal', 'keepState', 'sortService', '$timeout'
];
/**
@@ -30,7 +30,7 @@
* through pods declared in TestAPI.
*/
function PodsController($scope, $http, $filter, $state, $window, $uibModal, testapiApiUrl,
- raiseAlert, confirmModal, keepState, sortService) {
+ raiseAlert, confirmModal, keepState, sortService, $timeout) {
var ctrl = this;
ctrl.url = testapiApiUrl + '/pods';
ctrl.checkBox = []
@@ -48,6 +48,18 @@
ctrl.batchDelete = batchDelete;
ctrl.viewPod = viewPod
ctrl.sortBy = sortBy
+ ctrl.toastError = toastError
+ ctrl.toastSuccess = toastSuccess
+
+ function toastError() {
+ ctrl.showError = true
+ $timeout(function(){ ctrl.showError = false;}, 3000);
+ }
+
+ function toastSuccess() {
+ ctrl.showSuccess = true
+ $timeout(function(){ ctrl.showSuccess = false;}, 3000);
+ }
function sortBy(field){
ctrl.data.pods = sortService.sortFunction(ctrl.data.pods, field , ctrl.sorting[field] )
@@ -82,19 +94,21 @@
role: pod.role,
details: pod.details
};
- ctrl.podsRequest =
- $http.post(pods_url, body).success(function (data) {
- ctrl.showSuccess = true ;
+ ctrl.podsRequest = $http.post(pods_url, body)
+
+ ctrl.podsRequest.success(function (data) {
ctrl.success = "Create Success"
+ ctrl.toastSuccess()
ctrl.listPods();
}).catch(function (data) {
- ctrl.showError = true;
ctrl.error = data.statusText;
+ ctrl.toastError()
});
+ return ctrl.podsRequest
}
else{
- ctrl.showError = true;
ctrl.error = 'Name is missing.'
+ ctrl.toastError()
}
}
@@ -117,13 +131,15 @@
$http.get(reqURL).success(function (data) {
ctrl.data = data;
ctrl.sortBy("name")
- keepState.filter.podFilter = {
- 'name': ctrl.filterText
+ if(ctrl.filterText != undefined){
+ keepState.filter.podFilter = {
+ 'name': ctrl.filterText
+ }
}
}).catch(function (data) {
ctrl.data = null;
- ctrl.showError = true;
ctrl.error = data.statusText;
+ ctrl.toastError()
});
}
@@ -137,12 +153,12 @@
function podDelete(podName){
var pods_url = ctrl.url + "/" + podName
$http.delete(pods_url).success(function(){
- ctrl.showSuccess = true ;
ctrl.success = "Delete Success"
+ ctrl.toastSuccess()
ctrl.listPods();
}).catch(function (data) {
- ctrl.showError = true;
ctrl.error = data.statusText;
+ ctrl.toastError()
});
}
@@ -245,9 +261,10 @@
* inputs.
*/
function confirm() {
- $uibModalInstance.close();
if (angular.isDefined(ctrl.data.successHandler)) {
- ctrl.data.successHandler(ctrl.pod);
+ ctrl.data.successHandler(ctrl.pod).success( function(data){
+ $uibModalInstance.close();
+ })
}
}
diff --git a/testapi/opnfv_testapi/ui/components/projects/project/project.html b/testapi/opnfv_testapi/ui/components/projects/project/project.html
index b6a751c..2762fff 100644
--- a/testapi/opnfv_testapi/ui/components/projects/project/project.html
+++ b/testapi/opnfv_testapi/ui/components/projects/project/project.html
@@ -16,25 +16,11 @@
<div class="table-responsive">
<table class="table" ng-data="ctrl.data.pods">
<tbody>
- <tr style="padding:9px">
- <td class="podsTableTd">Id&nbsp;:</td>
- <td class="podsTableLeftTd">{{ctrl.data._id}}</td>
+ <tr ng-repeat-start="(index, detail) in ctrl.data_field" style="padding:9px">
+ <td class="podsTableTd">{{detail | capitalize}}&nbsp;:</td>
+ <td width="85%" class="podsTableLeftTd">{{ctrl.data[index]}}</td>
</tr>
- <tr style="padding:9px">
- <td class="podsTableTd">Name&nbsp;:</td>
- <td width="90%" class="podsTableLeftTd">{{ctrl.data.name}}</td>
- </tr>
- <tr style="padding:9px">
- <td class="podsTableTd">Creator&nbsp;:</td>
- <td width="90%" class="podsTableLeftTd">{{ctrl.data.creator}}</td>
- </tr>
- <tr style="padding:9px">
- <td class="podsTableTd">Created&nbsp;at&nbsp;:</td>
- <td width="90%" class="podsTableLeftTd">{{ctrl.data['creation_date']}}</td>
- </tr>
- <tr style="padding:9px">
- <td class="podsTableTd">Description&nbsp;:</td>
- <td width="90%" class="podsTableLeftTd">{{ctrl.data.description}}</td>
+ <tr ng-repeat-end=>
</tr>
</tbody>
</table>
diff --git a/testapi/opnfv_testapi/ui/components/projects/project/projectController.js b/testapi/opnfv_testapi/ui/components/projects/project/projectController.js
index 78b805d..9dc9e27 100644
--- a/testapi/opnfv_testapi/ui/components/projects/project/projectController.js
+++ b/testapi/opnfv_testapi/ui/components/projects/project/projectController.js
@@ -21,7 +21,7 @@
ProjectController.$inject = [
'$scope', '$http', '$filter', '$state', '$window', '$uibModal', 'testapiApiUrl','raiseAlert',
- 'confirmModal'
+ 'confirmModal', 'dataFieldService'
];
/**
@@ -30,12 +30,13 @@
* through projects declared in TestAPI.
*/
function ProjectController($scope, $http, $filter, $state, $window, $uibModal, testapiApiUrl,
- raiseAlert, confirmModal) {
+ raiseAlert, confirmModal, dataFieldService) {
var ctrl = this;
ctrl.name = $state.params['name'];
ctrl.url = testapiApiUrl + '/projects/' + ctrl.name;
ctrl.loadDetails = loadDetails;
+ ctrl.data_field = {}
/**
* This will contact the TestAPI to get a listing of declared projects.
@@ -45,6 +46,7 @@
ctrl.projectsRequest =
$http.get(ctrl.url).success(function (data) {
ctrl.data = data;
+ ctrl.data_field = dataFieldService.dataFunction(ctrl.data, ctrl.data_field)
}).catch(function (error) {
ctrl.data = null;
ctrl.showError = true;
diff --git a/testapi/opnfv_testapi/ui/components/projects/project/testCases/testCase/testCase.html b/testapi/opnfv_testapi/ui/components/projects/project/testCases/testCase/testCase.html
index f4bae41..509f39a 100644
--- a/testapi/opnfv_testapi/ui/components/projects/project/testCases/testCase/testCase.html
+++ b/testapi/opnfv_testapi/ui/components/projects/project/testCases/testCase/testCase.html
@@ -3,73 +3,11 @@
<div class="table-responsive">
<table class="table" ng-data="ctrl.data">
<tbody>
- <tr style="padding:9px">
- <td class="podsTableTd">Id&nbsp;:</td>
- <td class="podsTableLeftTd">{{ctrl.data._id}}</td>
+ <tr ng-repeat-start="(index, detail) in ctrl.data_field" style="padding:9px">
+ <td class="podsTableTd" >{{detail | capitalize}}&nbsp;:</td>
+ <td width="86%" class="podsTableLeftTd">{{ctrl.data[index]}}</td>
</tr>
- <tr style="padding:9px">
- <td class="podsTableTd">Name&nbsp;:</td>
- <td width="90%" class="podsTableLeftTd">{{ctrl.data.name}}</td>
- </tr>
- <tr style="padding:9px">
- <td class="podsTableTd">Project&nbsp;:</td>
- <td width="90%" class="podsTableLeftTd">{{ctrl.data.project_name}}</td>
- </tr>
- <tr style="padding:9px">
- <td class="podsTableTd">Creator&nbsp;:</td>
- <td width="90%" class="podsTableLeftTd">{{ctrl.data.creator}}</td>
- </tr>
- <tr style="padding:9px">
- <td class="podsTableTd">Tier&nbsp;:</td>
- <td width="90%" class="podsTableLeftTd">{{ctrl.data.tier}}</td>
- </tr>
- <tr style="padding:9px">
- <td class="podsTableTd">Blocking&nbsp;:</td>
- <td width="90%" class="podsTableLeftTd">{{ctrl.data.blocking}}</td>
- </tr>
- <tr style="padding:9px">
- <td class="podsTableTd">CI&nbsp;Loop&nbsp;:</td>
- <td width="90%" class="podsTableLeftTd">{{ctrl.data.ci_loop}}</td>
- </tr>
- <tr style="padding:9px">
- <td class="podsTableTd">Tags&nbsp;:</td>
- <td width="90%" class="podsTableLeftTd">{{ctrl.data.tags}}</td>
- </tr>
- <tr style="padding:9px">
- <td class="podsTableTd">Version&nbsp;:</td>
- <td width="90%" class="podsTableLeftTd">{{ctrl.data.version}}</td>
- </tr>
- <tr style="padding:9px">
- <td class="podsTableTd">Created&nbsp;at&nbsp;:</td>
- <td width="90%" class="podsTableLeftTd">{{ctrl.data['creation_date']}}</td>
- </tr>
- <tr style="padding:9px">
- <td class="podsTableTd">Dependencies&nbsp;:</td>
- <td width="90%" class="podsTableLeftTd">{{ctrl.data.dependencies}}</td>
- </tr>
- <tr style="padding:9px">
- <td class="podsTableTd">Trust&nbsp;:</td>
- <td width="90%" class="podsTableLeftTd">{{ctrl.data.trust}}</td>
- </tr>
- <tr style="padding:9px">
- <td class="podsTableTd">Criteria&nbsp;:</td>
- <td width="90%" class="podsTableLeftTd">{{ctrl.data.criteria}}</td>
- </tr>
- <tr style="padding:9px">
- <td class="podsTableTd">Catalog&nbsp;Description&nbsp;:</td>
- <td width="90%" class="podsTableLeftTd">{{ctrl.data.catalog_description}}</td>
- </tr>
- <tr style="padding:9px">
- <td class="podsTableTd">URL&nbsp;:</td>
- <td width="90%" class="podsTableLeftTd">{{ctrl.data.url}}</td>
- </tr>
- <tr style="padding:9px">
- <td class="podsTableTd">Run&nbsp;:</td>
- <td width="90%" class="podsTableLeftTd">{{ctrl.data.run}}</td>
- </tr>
- <tr style="padding:9px">
- <td class="podsTableTd">Description&nbsp;:</td>
- <td width="90%" class="podsTableLeftTd">{{ctrl.data.description}}</td>
+ <tr ng-repeat-end=>
</tr>
</tbody>
</table>
diff --git a/testapi/opnfv_testapi/ui/components/projects/project/testCases/testCase/testCaseController.js b/testapi/opnfv_testapi/ui/components/projects/project/testCases/testCase/testCaseController.js
index a38b633..6f93fc1 100644
--- a/testapi/opnfv_testapi/ui/components/projects/project/testCases/testCase/testCaseController.js
+++ b/testapi/opnfv_testapi/ui/components/projects/project/testCases/testCase/testCaseController.js
@@ -21,7 +21,7 @@
TestCaseController.$inject = [
'$scope', '$http', '$filter', '$state', '$window', '$uibModal', 'testapiApiUrl','raiseAlert',
- 'confirmModal'
+ 'confirmModal', 'dataFieldService'
];
/**
@@ -30,13 +30,14 @@
* through projects declared in TestAPI.
*/
function TestCaseController($scope, $http, $filter, $state, $window, $uibModal, testapiApiUrl,
- raiseAlert, confirmModal) {
+ raiseAlert, confirmModal, dataFieldService) {
var ctrl = this;
ctrl.name = $state.params['name'];
ctrl.projectName = $state.params['project_name'];
ctrl.url = testapiApiUrl + '/projects/' + ctrl.projectName + "/cases/" + ctrl.name;
ctrl.loadDetails = loadDetails;
+ ctrl.data_field = {}
/**
* This will contact the TestAPI to get a listing of declared projects.
@@ -46,6 +47,7 @@
ctrl.projectsRequest =
$http.get(ctrl.url).success(function (data) {
ctrl.data = data;
+ ctrl.data_field = dataFieldService.dataFunction(ctrl.data, ctrl.data_field)
}).catch(function (error) {
ctrl.data = null;
ctrl.showError = true;
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..04baa9c 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,64 @@
<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 ng-class="{'show': testCasesCtrl.showError}" id="toast" class="error">
+ <span class="glyphicon glyphicon-exclamation-sign" aria-hidden="true" ></span>
+ {{testCasesCtrl.error}}</div>
+ <div ng-class="{'show': testCasesCtrl.showSuccess}" id="toast" class="success">
+ <span class="glyphicon glyphicon-ok" aria-hidden="true"></span>
+ {{testCasesCtrl.success}}</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..ea0498a 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', '$timeout'
];
/**
@@ -31,7 +31,7 @@
* in them.
*/
function TestCasesController($scope, $http, $filter, $state, $window, $uibModal, testapiApiUrl,
- raiseAlert, confirmModal) {
+ raiseAlert, confirmModal, authenticate, $timeout) {
var ctrl = this;
ctrl.loadDetails = loadDetails;
ctrl.name = $state.params['name'];
@@ -49,29 +49,40 @@
ctrl.checkBox = [];
ctrl.checkBoxList = [];
+ ctrl.toastError = toastError
+ ctrl.toastSuccess = toastSuccess
+
+ function toastError() {
+ ctrl.showError = true
+ $timeout(function(){ ctrl.showError = false;}, 3000);
+ }
+
+ function toastSuccess() {
+ ctrl.showSuccess = true
+ $timeout(function(){ ctrl.showSuccess = false;}, 3000);
+ }
/**
* This will contact the TestAPI to create a new test case.
*/
function createTestCase(name, testcase) {
- ctrl.showError = false;
- ctrl.showSuccess = false;
if(testcase.name != "" && testcase.name!=null){
var testCase_url = ctrl.requestUrl;
- ctrl.testCasesRequest =
- $http.post(testCase_url, testcase).success(function (data){
- ctrl.showSuccess = true ;
- ctrl.successMessage = "Testcase is successfully created."
+ ctrl.testCasesRequest = $http.post(testCase_url, testcase)
+ ctrl.testCasesRequest.success(function (data){
+ ctrl.success = "Testcase is successfully created."
loadDetails();
+ ctrl.toastSuccess()
})
.catch(function (data) {
- ctrl.showError = true;
ctrl.error = data.statusText;
+ ctrl.toastError();
});
+ return ctrl.testCasesRequest;
}
else{
- ctrl.showError = true;
ctrl.error = 'Name is missing.'
+ ctrl.toastError();
}
}
@@ -114,24 +125,23 @@
* This will contact the TestAPI to update an existing test case.
*/
function updateTestCase(name, testCase) {
- ctrl.showError = false;
- ctrl.showSuccess = false;
if(testCase.name != ""){
var testCase_url = ctrl.requestUrl + '/' + name;
- ctrl.testCasesRequest =
- $http.put(testCase_url, testCase).success(function (data){
- ctrl.showSuccess = true ;
- ctrl.successMessage = "Test case is successfully updated"
+ ctrl.testCasesRequest = $http.put(testCase_url, testCase)
+ ctrl.testCasesRequest.success(function (data){
+ ctrl.success = "Test case is successfully updated"
loadDetails();
+ ctrl.toastSuccess();
})
.catch(function (data) {
- ctrl.showError = true;
ctrl.error = data.statusText;
+ ctrl.toastError()
});
+ return ctrl.testCasesRequest;
}
else{
- ctrl.showError = true;
ctrl.error = 'Name is missing.'
+ ctrl.toastError()
}
}
@@ -139,16 +149,14 @@
* This will contact the TestAPI to delete an existing test case.
*/
function deleteTestCase(name) {
- ctrl.showError = false;
- ctrl.showSuccess = false;
ctrl.testCasesRequest =
$http.delete(ctrl.requestUrl+"/"+name).success(function (data) {
loadDetails();
- ctrl.showSuccess = true ;
- ctrl.successMessage = "Test case is successfully deleted"
+ ctrl.success = "Test case is successfully deleted";
+ ctrl.toastSuccess();
}).catch(function (error) {
- ctrl.showError = true;
- ctrl.error = data.statusText;
+ ctrl.error = error.statusText;
+ ctrl.toastError();
});
}
@@ -218,8 +226,8 @@
ctrl.data = data;
}).catch(function (error) {
ctrl.data = null;
- ctrl.showError = true;
ctrl.error = error.statusText;
+ ctrl.toastError()
});
}
ctrl.loadDetails();
@@ -271,9 +279,15 @@
* inputs.
*/
function confirm() {
- $uibModalInstance.close();
if (angular.isDefined(ctrl.data.successHandler)) {
- ctrl.data.successHandler(ctrl.name, ctrl.testcase);
+ if(ctrl.testcase.name){
+ ctrl.data.successHandler(ctrl.name, ctrl.testcase).success( function(){
+ $uibModalInstance.close();
+ })
+ }
+ else{
+ ctrl.data.successHandler(ctrl.name, ctrl.testcase)
+ }
}
}
diff --git a/testapi/opnfv_testapi/ui/components/projects/projects.html b/testapi/opnfv_testapi/ui/components/projects/projects.html
index 5d514d1..3098aa2 100644
--- a/testapi/opnfv_testapi/ui/components/projects/projects.html
+++ b/testapi/opnfv_testapi/ui/components/projects/projects.html
@@ -21,16 +21,12 @@
<input type="text" class="form-control search" ng-enter="ctrl.listProjects()" ng-Model="ctrl.filterText" style="width:80%;" placeholder="Search By Name">
</div>
</div>
-<div class='clo-md-12'>
- <div ng-show="ctrl.showError" class="alert alert-danger" role="alert">
- <span class="pull-right">&nbsp;{{ctrl.error}}</span>
- <span class="glyphicon glyphicon-exclamation-sign pull-right" aria-hidden="true" >Error:</span>
- </div>
- <div ng-show="ctrl.showSuccess" class="alert alert-success" role="alert">
- <span class="pull-right">&nbsp;{{ctrl.success}}</span>
- <span class="glyphicon glyphicon-ok pull-right" aria-hidden="true"></span>
- </div>
-</div>
+<div ng-class="{'show': ctrl.showError}" id="toast" class="error">
+ <span class="glyphicon glyphicon-exclamation-sign" aria-hidden="true" ></span>
+ {{ctrl.error}}</div>
+<div ng-class="{'show': ctrl.showSuccess}" id="toast" class="success">
+ <span class="glyphicon glyphicon-ok" aria-hidden="true"></span>
+ {{ctrl.success}}</div>
<div class='clo-md-12' style="padding-right:0px">
<div class="table-responsive">
<table class="table table-bordered table-hover" ng-data="ctrl.data.projects">
diff --git a/testapi/opnfv_testapi/ui/components/projects/projectsController.js b/testapi/opnfv_testapi/ui/components/projects/projectsController.js
index 07a58fe..42100bd 100644
--- a/testapi/opnfv_testapi/ui/components/projects/projectsController.js
+++ b/testapi/opnfv_testapi/ui/components/projects/projectsController.js
@@ -21,7 +21,7 @@
ProjectsController.$inject = [
'$scope', '$http', '$filter', '$state', '$window', '$uibModal', 'testapiApiUrl',
- 'raiseAlert', 'confirmModal', 'authenticate', 'keepState', 'sortService'
+ 'raiseAlert', 'confirmModal', 'authenticate', 'keepState', 'sortService', '$timeout'
];
/**
@@ -30,7 +30,7 @@
* through projects declared in TestAPI.
*/
function ProjectsController($scope, $http, $filter, $state, $window, $uibModal, testapiApiUrl,
- raiseAlert, confirmModal, authenticate, keepState, sortService) {
+ raiseAlert, confirmModal, authenticate, keepState, sortService, $timeout) {
var ctrl = this;
ctrl.url = testapiApiUrl + '/projects';
@@ -51,27 +51,41 @@
ctrl.name = '';
ctrl.details = '';
ctrl.ascending = false;
+ ctrl.toastError = toastError
+ ctrl.toastSuccess = toastSuccess
+
+ function toastError() {
+ ctrl.showError = true
+ $timeout(function(){ ctrl.showError = false;}, 7000);
+ }
+
+ function toastSuccess() {
+ ctrl.showSuccess = true
+ $timeout(function(){ ctrl.showSuccess = false;}, 7000);
+ }
/**
* This will contact the TestAPI to create a new project.
*/
function create(project) {
- ctrl.showError = false;
- ctrl.showSuccess = false;
var projects_url = ctrl.url;
var body = {
name: project.name,
description: project.description
};
- ctrl.projectsRequest =
- $http.post(projects_url, body).success(function (data){
- ctrl.showSuccess = true ;
- ctrl.success = "Project is successfully created."
+ ctrl.projectsRequest = $http.post(projects_url, body)
+ ctrl.projectsRequest.success(function (data){
+ ctrl.success = "Project is successfully created.";
ctrl.listProjects();
+ ctrl.toastSuccess();
+ ctrl.request = true;
}).catch(function (data) {
- ctrl.showError = true;
ctrl.error = data.statusText;
+ ctrl.toastError();
+ ctrl.request = false;
});
+
+ return ctrl.projectsRequest
}
function sortByName(){
@@ -135,16 +149,17 @@
ctrl.showError = false;
ctrl.showSuccess = false;
var projectUrl = ctrl.url + '/' + name;
- ctrl.testCasesRequest =
- $http.put(projectUrl, project).success(function (data){
- ctrl.showSuccess = true ;
+ ctrl.projectRequest = $http.put(projectUrl, project)
+ ctrl.projectRequest.success(function (data){
ctrl.success = "Project is successfully updated."
- listProjects();
+ ctrl.listProjects();
+ ctrl.toastSuccess();
})
.catch(function (data) {
- ctrl.showError = true;
ctrl.error = data.statusText;
+ ctrl.toastError();
});
+ return ctrl.projectRequest
}
/**
@@ -167,13 +182,15 @@
ctrl.resultsRequest =
$http.get(content_url).success(function (data) {
ctrl.data = data;
- keepState.filter.projectFilter = {
- 'name': ctrl.filterText
+ if(ctrl.filterText != undefined){
+ keepState.filter.projectFilter = {
+ 'name': ctrl.filterText
+ }
}
}).catch(function (data) {
ctrl.data = null;
- ctrl.showError = true;
ctrl.error = data.statusText;
+ ctrl.toastError();
});
}
@@ -188,13 +205,12 @@
function projectDelete(projectName){
var projectUrl = ctrl.url + "/" + projectName
$http.delete(projectUrl).success(function(){
- ctrl.showSuccess = true ;
ctrl.success = "Projects is successfully deleted"
+ ctrl.toastSuccess();
ctrl.listProjects();
}).catch(function (data) {
- ctrl.showError = true;
- ctrl.showSuccess = false;
ctrl.error = data.statusText;
+ ctrl.toastError();
});
}
@@ -275,11 +291,15 @@
function confirm() {
if (angular.isDefined(ctrl.data.successHandler)) {
if(ctrl.project.name != ""){
- $uibModalInstance.close();
+ var success = false;
if(ctrl.data.project){
- ctrl.data.successHandler(ctrl.projectName, ctrl.project);
+ ctrl.data.successHandler(ctrl.projectName, ctrl.project).success(function (data){
+ $uibModalInstance.close();
+ })
}else{
- ctrl.data.successHandler(ctrl.project);
+ ctrl.data.successHandler(ctrl.project).success(function (data){
+ $uibModalInstance.close();
+ })
}
}else{
ctrl.showCreateError = true;
diff --git a/testapi/opnfv_testapi/ui/components/results/result/result.html b/testapi/opnfv_testapi/ui/components/results/result/result.html
index 52d794e..041f244 100644
--- a/testapi/opnfv_testapi/ui/components/results/result/result.html
+++ b/testapi/opnfv_testapi/ui/components/results/result/result.html
@@ -3,78 +3,16 @@
<div class="table-responsive">
<table class="table" ng-data="ctrl.data.pods">
<tbody>
- <tr style="padding:9px">
- <td class="podsTableTd">Id&nbsp;:</td>
- <td class="podsTableLeftTd">{{ctrl.data._id}}</td>
- </tr>
- <tr style="padding:9px">
- <td class="podsTableTd">Pod&nbsp;Name:</td>
- <td width="90%" class="podsTableLeftTd">{{ctrl.data.pod_name}}</td>
- </tr>
- <tr style="padding:9px">
- <td class="podsTableTd">Project&nbsp;Name:</td>
- <td width="90%" class="podsTableLeftTd">{{ctrl.data.project_name}}</td>
- </tr>
- <tr style="padding:9px">
- <td class="podsTableTd">Case&nbsp;Name&nbsp;:</td>
- <td width="90%" class="podsTableLeftTd">{{ctrl.data.case_name}}</td>
- </tr>
- <tr style="padding:9px">
- <td class="podsTableTd">Installer&nbsp;:</td>
- <td width="90%" class="podsTableLeftTd">{{ctrl.data.installer}}</td>
- </tr>
- <tr style="padding:9px">
- <td class="podsTableTd">Version&nbsp;:</td>
- <td width="90%" class="podsTableLeftTd">{{ctrl.data.version}}</td>
- </tr>
- <tr style="padding:9px">
- <td class="podsTableTd">Scenario&nbsp;:</td>
- <td width="90%" class="podsTableLeftTd">{{ctrl.data.scenario}}</td>
- </tr>
- <tr style="padding:9px">
- <td class="podsTableTd">Build&nbsp;tag&nbsp;:</td>
- <td width="90%" class="podsTableLeftTd">{{ctrl.data['build_tag']}}</td>
+ <tr ng-repeat-start="(index, detail) in ctrl.data_field" style="padding:9px">
+ <td class="podsTableTd">{{detail | capitalize}}&nbsp;:</td>
+ <td width="90%" class="podsTableLeftTd">{{ctrl.data[index]}}</td>
</tr>
- <tr style="padding:9px">
- <td class="podsTableTd">Criteria&nbsp;:</td>
- <td width="90%" class="podsTableLeftTd">{{ctrl.data.criteria}}</td>
- </tr>
- <tr style="padding:9px">
- <td class="podsTableTd">Start&nbsp;Date:</td>
- <td width="90%" class="podsTableLeftTd">{{ctrl.data.start_date}}</td>
- </tr>
- <tr style="padding:9px">
- <td class="podsTableTd">Stop&nbsp;Date&nbsp;:</td>
- <td width="90%" class="podsTableLeftTd">{{ctrl.data.stop_date}}</td>
+ <tr ng-repeat-end=>
</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 cb5dd28..2726704 100644
--- a/testapi/opnfv_testapi/ui/components/results/result/resultController.js
+++ b/testapi/opnfv_testapi/ui/components/results/result/resultController.js
@@ -21,7 +21,7 @@
ResultController.$inject = [
'$scope', '$http', '$filter', '$state', '$window', '$uibModal', 'testapiApiUrl','raiseAlert',
- 'confirmModal'
+ 'confirmModal', 'dataFieldService'
];
/**
@@ -30,13 +30,16 @@
* through result declared in TestAPI.
*/
function ResultController($scope, $http, $filter, $state, $window, $uibModal, testapiApiUrl,
- raiseAlert, confirmModal) {
+ raiseAlert, confirmModal, dataFieldService) {
var ctrl = this;
ctrl.url = testapiApiUrl + '/results';
ctrl._id = $state.params['_id'];
ctrl.loadDetails = loadDetails
- ctrl.showTrustIndicator = showTrustIndicator
- ctrl.showDetails = showDetails
+ ctrl.data_field = {}
+
+ ctrl.json = {};
+ ctrl.json.string = '{"id": ""}';
+ ctrl.json.object = JSON.parse(ctrl.json.string);
/**
*Contact the testapi and retrevie the result details
@@ -47,6 +50,10 @@
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)
+ delete ctrl.data.details;
+ ctrl.data_field = dataFieldService.dataFunction(ctrl.data, ctrl.data_field)
}).catch(function (error) {
ctrl.data = null;
ctrl.showError = true;
@@ -54,13 +61,6 @@
});
}
- 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/modals/customModal.html b/testapi/opnfv_testapi/ui/components/scenarios/modals/customModal.html
index 0cd2663..4225749 100644
--- a/testapi/opnfv_testapi/ui/components/scenarios/modals/customModal.html
+++ b/testapi/opnfv_testapi/ui/components/scenarios/modals/customModal.html
@@ -6,14 +6,16 @@
<legend>{{customModalCtrl.data.text}}</legend>
<div class="row">
<div class="update-project">
- <label for="cpid" class="control-label col-sm-4">Custom: </label>
+ <label for="cpid" class="control-label col-sm-2">Custom: </label>
<table cellpadding="0" cellspacing="0">
<tbody>
<tr>
<td>
<div class="col-sm-12">
<input type="text" class="form-control" ng-model="customModalCtrl.custom"/>
- <p class="help-block"></p>
+ <p class="help-block">
+ Please separate multiple customs with space or comma
+ </p>
</div>
</td>
</tr>
diff --git a/testapi/opnfv_testapi/ui/components/scenarios/scenario/scenario.html b/testapi/opnfv_testapi/ui/components/scenarios/scenario/scenario.html
index 4f0a580..d6d4257 100644
--- a/testapi/opnfv_testapi/ui/components/scenarios/scenario/scenario.html
+++ b/testapi/opnfv_testapi/ui/components/scenarios/scenario/scenario.html
@@ -225,14 +225,10 @@
</div>
</div>
<div class="row" style="margin-bottom:24px;"></div>
-<div class='clo-md-12'>
- <div ng-show="ctrl.showError" class="alert alert-danger" role="alert">
- <span class="pull-right">&nbsp;{{ctrl.error}}</span>
- <span class="glyphicon glyphicon-exclamation-sign pull-right" aria-hidden="true" >Error:</span>
- </div>
- <div ng-show="ctrl.showSuccess" class="alert alert-success" role="alert">
- <span class="pull-right">&nbsp;{{ctrl.success}}</span>
- <span class="glyphicon glyphicon-ok pull-right" aria-hidden="true"></span>
- </div>
-</div>
+<div ng-class="{'show': ctrl.showError}" id="toast" class="error">
+ <span class="glyphicon glyphicon-exclamation-sign" aria-hidden="true" ></span>
+ {{ctrl.error}}</div>
+<div ng-class="{'show': ctrl.showSuccess}" id="toast" class="success">
+ <span class="glyphicon glyphicon-ok" aria-hidden="true"></span>
+ {{ctrl.success}}</div>
<div class="row" style="margin-bottom:24px;"></div> \ No newline at end of file
diff --git a/testapi/opnfv_testapi/ui/components/scenarios/scenario/scenarioController.js b/testapi/opnfv_testapi/ui/components/scenarios/scenario/scenarioController.js
index a0cd5eb..e17718f 100644
--- a/testapi/opnfv_testapi/ui/components/scenarios/scenario/scenarioController.js
+++ b/testapi/opnfv_testapi/ui/components/scenarios/scenario/scenarioController.js
@@ -21,7 +21,7 @@
ScenarioController.$inject = [
'$scope', '$http', '$filter', '$state', '$window', '$uibModal', 'testapiApiUrl','raiseAlert',
- 'confirmModal', 'authenticate'
+ 'confirmModal', 'authenticate', '$timeout'
];
/**
@@ -30,7 +30,7 @@
* through Scenario declared in TestAPI.
*/
function ScenarioController($scope, $http, $filter, $state, $window, $uibModal, testapiApiUrl,
- raiseAlert, confirmModal, authenticate) {
+ raiseAlert, confirmModal, authenticate, $timeout) {
var ctrl = this;
ctrl.name = $state.params['name'];
ctrl.url = testapiApiUrl + '/scenarios?name=' + ctrl.name;
@@ -73,7 +73,18 @@
ctrl.buttonInstaller = true
ctrl.buttonVersion = true
ctrl.buttonProject = true
+ ctrl.toastError = toastError
+ ctrl.toastSuccess = toastSuccess
+ function toastError() {
+ ctrl.showError = true
+ $timeout(function(){ ctrl.showError = false;}, 3000);
+ }
+
+ function toastSuccess() {
+ ctrl.showSuccess = true
+ $timeout(function(){ ctrl.showSuccess = false;}, 3000);
+ }
/**
* This will contact the TestAPI to get a listing of declared projects.
*/
@@ -84,8 +95,8 @@
ctrl.data = data;
}).catch(function (error) {
ctrl.data = null;
- ctrl.showError = true;
ctrl.error = error.statusText
+ ctrl.toastError()
});
}
@@ -203,13 +214,13 @@
function deleteInstaller(data){
ctrl.installerReqest = testapiApiUrl+ "/scenarios/"+ ctrl.name + "/installers"
$http.delete(ctrl.installerReqest, {data: data.installers, headers: {'Content-Type': 'application/json'}}).success(function (data){
- ctrl.showSuccess = true ;
ctrl.success = "Installer is successfully deleted."
+ ctrl.toastSuccess();
ctrl.loadDetails();
})
.catch(function (data) {
- ctrl.showError = true;
ctrl.error = data.statusText;
+ ctrl.toastError()
});
}
@@ -225,16 +236,18 @@
function addInstaller(installer){
var installers = []
installers.push(installer)
- ctrl.installerReqest = testapiApiUrl+ "/scenarios/"+ ctrl.name + "/installers"
- $http.post(ctrl.installerReqest, installers).success(function (data){
- ctrl.showSuccess = true ;
+ ctrl.installerRequestUrl = testapiApiUrl+ "/scenarios/"+ ctrl.name + "/installers"
+ ctrl.installerRequest = $http.post(ctrl.installerRequestUrl, installers)
+ ctrl.installerRequest.success(function (data){
ctrl.success = "Installers are successfully updated."
ctrl.loadDetails();
+ ctrl.toastSuccess();
})
.catch(function (data) {
- ctrl.showError = true;
ctrl.error = data.statusText;
+ ctrl.toastError();
});
+ return ctrl.installerRequest
}
function openAddInstaller(){
@@ -254,16 +267,18 @@
}
function addVersion(versions, installer){
- ctrl.versionReqest = testapiApiUrl+ "/scenarios/"+ ctrl.name + "/versions?installer="+installer
- $http.post(ctrl.versionReqest, versions).success(function (data){
- ctrl.showSuccess = true ;
+ ctrl.versionRequestUrl = testapiApiUrl+ "/scenarios/"+ ctrl.name + "/versions?installer="+installer
+ ctrl.versionRequest = $http.post(ctrl.versionRequestUrl, versions)
+ ctrl.versionRequest.success(function (data){
ctrl.success = "Versions are successfully updated."
ctrl.loadDetails();
+ ctrl.toastSuccess()
})
.catch(function (data) {
- ctrl.showError = true;
ctrl.error = data.statusText;
+ ctrl.toastError()
});
+ return ctrl.versionRequest;
}
function openDeleteVersionModal(version, installer){
@@ -279,13 +294,13 @@
function deleteVersion(data){
ctrl.versionReqest = testapiApiUrl+ "/scenarios/"+ ctrl.name + "/versions?installer="+data.installer
$http.delete(ctrl.versionReqest, {data: data.version, headers: {'Content-Type': 'application/json'}}).success(function (data){
- ctrl.showSuccess = true ;
ctrl.success = "Versions are successfully deleted."
ctrl.loadDetails();
+ ctrl.toastSuccess();
})
.catch(function (data) {
- ctrl.showError = true;
ctrl.error = data.statusText;
+ ctrl.toastError();
});
}
@@ -307,16 +322,18 @@
}
function addProject(project, version, installer){
- ctrl.projectReqest = testapiApiUrl+ "/scenarios/"+ ctrl.name + "/projects?installer="+installer+"&version="+version
- $http.post(ctrl.projectReqest, project).success(function (data){
- ctrl.showSuccess = true ;
+ ctrl.projectRequestUrl = testapiApiUrl+ "/scenarios/"+ ctrl.name + "/projects?installer="+installer+"&version="+version
+ ctrl.projectRequest= $http.post(ctrl.projectRequestUrl, project)
+ ctrl.projectRequest.success(function (data){
ctrl.success = "Projects are successfully updated."
ctrl.loadDetails();
+ ctrl.toastSuccess();
})
.catch(function (data) {
- ctrl.showError = true;
ctrl.error = data.statusText;
+ ctrl.toastError();
});
+ return ctrl.projectRequest;
}
function openAddProjectModal(version, installer){
@@ -338,16 +355,18 @@
}
function addCustom(custom,project,version,installer){
- ctrl.customReqest = testapiApiUrl+ "/scenarios/"+ ctrl.name + "/customs?installer="+installer+"&version="+version+"&project="+ project
- $http.post(ctrl.customReqest, custom).success(function (data){
- ctrl.showSuccess = true ;
+ ctrl.customRequestUrl = testapiApiUrl+ "/scenarios/"+ ctrl.name + "/customs?installer="+installer+"&version="+version+"&project="+ project
+ ctrl.customRequest = $http.post(ctrl.customRequestUrl, custom)
+ ctrl.customRequest.success(function (data){
ctrl.success = "Customs are successfully updated."
ctrl.loadDetails();
+ ctrl.toastSuccess();
})
.catch(function (data) {
- ctrl.showError = true;
ctrl.error = data.statusText;
+ ctrl.toastError();
});
+ return ctrl.customRequest
}
function openDeleteCustomModal(custom,project,version,installer){
@@ -365,13 +384,13 @@
function deleteCustom(data){
ctrl.customReqest = testapiApiUrl+ "/scenarios/"+ ctrl.name + "/customs?installer="+data.installer+"&version="+data.version+"&project="+ data.project
$http.delete(ctrl.customReqest, {data: data.customs, headers: {'Content-Type': 'application/json'}}).success(function (data){
- ctrl.showSuccess = true ;
ctrl.success = "Customs are successfully deleted."
ctrl.loadDetails();
+ ctrl.toastSuccess();
})
.catch(function (data) {
- ctrl.showError = true;
ctrl.error = data.statusText;
+ ctrl.toastError();
});
}
@@ -408,13 +427,13 @@
function deleteProject(data){
ctrl.projectReqest = testapiApiUrl+ "/scenarios/"+ ctrl.name + "/projects?installer="+data.installer+"&version="+data.version
$http.delete(ctrl.projectReqest, {data: data.projects, headers: {'Content-Type': 'application/json'}}).success(function (data){
- ctrl.showSuccess = true ;
- ctrl.success = "Projects are successfully Deleted."
+ ctrl.success = "Projects are successfully Deleted.";
+ ctrl.toastSuccess();
ctrl.loadDetails();
})
.catch(function (data) {
- ctrl.showError = true;
ctrl.error = data.statusText;
+ ctrl.toastError();
});
}
@@ -443,8 +462,11 @@
ctrl.customs = custom.split(/[ ,]+/).filter(Boolean);
}
console.log(ctrl.customs)
- ctrl.data.successHandler(ctrl.customs,ctrl.data.project,ctrl.data.version,ctrl.data.installer);
- $uibModalInstance.dismiss('cancel');
+ ctrl.data.successHandler(
+ ctrl.customs, ctrl.data.project,
+ ctrl.data.version,ctrl.data.installer).success(function(){
+ $uibModalInstance.dismiss('cancel');
+ });
}
@@ -486,8 +508,10 @@
*/
function confirm() {
ctrl.projects.push(ctrl.project)
- ctrl.data.successHandler(ctrl.projects, ctrl.data.version, ctrl.data.installer);
- $uibModalInstance.dismiss('cancel');
+ ctrl.data.successHandler(
+ ctrl.projects, ctrl.data.version, ctrl.data.installer).success( function(){
+ $uibModalInstance.dismiss('cancel');
+ });
}
@@ -545,8 +569,9 @@
*/
function confirm() {
ctrl.versions.push(ctrl.version)
- ctrl.data.successHandler(ctrl.versions, ctrl.data.installer);
- $uibModalInstance.dismiss('cancel');
+ ctrl.data.successHandler(ctrl.versions, ctrl.data.installer).success(function(){
+ $uibModalInstance.dismiss('cancel');
+ });
}
diff --git a/testapi/opnfv_testapi/ui/components/scenarios/scenarios.html b/testapi/opnfv_testapi/ui/components/scenarios/scenarios.html
index 9057b0f..8d23449 100644
--- a/testapi/opnfv_testapi/ui/components/scenarios/scenarios.html
+++ b/testapi/opnfv_testapi/ui/components/scenarios/scenarios.html
@@ -10,16 +10,12 @@
<i class="fa fa-plus"></i>Create</button>
</div>
</div>
-<div class='clo-md-12'>
- <div ng-show="ctrl.showError" class="alert alert-danger" role="alert">
- <span class="pull-right">&nbsp;{{ctrl.error}}</span>
- <span class="glyphicon glyphicon-exclamation-sign pull-right" aria-hidden="true" >Error:</span>
- </div>
- <div ng-show="ctrl.showCreateSuccess" class="alert alert-success" role="alert">
- <span class="pull-right">&nbsp;{{ctrl.success}}</span>
- <span class="glyphicon glyphicon-ok pull-right" aria-hidden="true"></span>
- </div>
-</div>
+<div ng-class="{'show': ctrl.showError}" id="toast" class="error">
+ <span class="glyphicon glyphicon-exclamation-sign" aria-hidden="true" ></span>
+ {{ctrl.error}}</div>
+<div ng-class="{'show': ctrl.showSuccess}" id="toast" class="success">
+ <span class="glyphicon glyphicon-ok" aria-hidden="true"></span>
+ {{ctrl.success}}</div>
<div class='clo-md-12' style="padding-right:0px">
<div class="table-responsive">
<table class="table table-bordered table-hover" ng-data="ctrl.data.scenarios">
@@ -27,7 +23,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..0aa5bf0 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', '$timeout'
];
/**
@@ -30,7 +30,7 @@
* through projects declared in TestAPI.
*/
function ScenariosController($scope, $http, $filter, $state, $window, $uibModal, testapiApiUrl,
- raiseAlert, confirmModal) {
+ raiseAlert, confirmModal, sortService, $timeout) {
var ctrl = this;
ctrl.url = testapiApiUrl + '/scenarios';
@@ -44,8 +44,21 @@
ctrl.deleteScenario = deleteScenario;
ctrl.openBatchDeleteModal = openBatchDeleteModal;
ctrl.deleteBatchScenario = deleteBatchScenario
-
+ ctrl.sortBy = sortBy
ctrl.checkBox = [];
+ ctrl.sortName = false
+ ctrl.toastError = toastError
+ ctrl.toastSuccess = toastSuccess
+
+ function toastError() {
+ ctrl.showError = true
+ $timeout(function(){ ctrl.showError = false;}, 3000);
+ }
+
+ function toastSuccess() {
+ ctrl.showSuccess = true
+ $timeout(function(){ ctrl.showSuccess = false;}, 3000);
+ }
function openUpdateModal(name){
$uibModal.open({
@@ -68,16 +81,21 @@
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 =
$http.delete(scenarioURL).success(function (data){
- ctrl.showCreateSuccess = true;
ctrl.success = "Scenario is successfully deleted.";
ctrl.listScenarios();
+ ctrl.toastSuccess();
}).catch(function (data) {
- ctrl.showError = true;
ctrl.error = data.statusText;
+ ctrl.toastError()
});
}
@@ -111,15 +129,21 @@
var body = {
"name": newName
}
- ctrl.scenarioRequest =
- $http.put(scenarioURL, body).success(function (data){
- ctrl.showCreateSuccess = true;
+ if(newName){
+ ctrl.scenarioRequest = $http.put(scenarioURL, body)
+ ctrl.scenarioRequest.success(function (data){
ctrl.success = "Scenario is successfully Updated."
- ctrl.listScenarios()
+ ctrl.listScenarios();
+ ctrl.toastSuccess();
}).catch(function (data) {
- ctrl.showError = true;
ctrl.error = data.statusText;
+ ctrl.toastError();
});
+ return ctrl.scenarioRequest
+ }else{
+ ctrl.error = "Name is missing";
+ ctrl.toastError();
+ }
}
function viewScenario(name){
@@ -127,14 +151,17 @@
}
function createScenario(scenario) {
- ctrl.scenarioRequest =
- $http.post(ctrl.url, scenario).success(function (data){
- ctrl.showCreateSuccess = true;
- ctrl.success = "Scenario is successfully created."
+ ctrl.scenarioRequest = $http.post(ctrl.url, scenario)
+
+ ctrl.scenarioRequest.success(function (data){
+ ctrl.success = "Scenario is successfully created.";
+ ctrl.toastSuccess();
}).catch(function (data) {
- ctrl.showError = true;
ctrl.error = data.statusText;
+ ctrl.toastError();
});
+
+ return ctrl.scenarioRequest;
}
function listScenarios() {
@@ -142,10 +169,11 @@
ctrl.resultsRequest =
$http.get(ctrl.url).success(function (data) {
ctrl.data = data;
+ ctrl.sortBy()
}).catch(function (data) {
ctrl.data = null;
- ctrl.showError = true;
ctrl.error = data.statusText;
+ ctrl.toastError();
});
}
@@ -176,8 +204,8 @@
* edit the project's details
*/
angular.module('testapiApp').controller('scenarioModalController', scenarioModalController);
- scenarioModalController.$inject = ['$scope', '$uibModal', '$uibModalInstance', 'data'];
- function scenarioModalController($scope, $uibModal, $uibModalInstance, data) {
+ scenarioModalController.$inject = ['$scope', '$uibModal', '$uibModalInstance', 'data', '$q'];
+ function scenarioModalController($scope, $uibModal, $uibModalInstance, data, $q) {
var ctrl = this;
ctrl.confirm = confirm;
ctrl.cancel = cancel;
@@ -194,8 +222,9 @@
* inputs.
*/
function confirm() {
- ctrl.data.successHandler(ctrl.scenario);
- $uibModalInstance.dismiss('cancel');
+ ctrl.data.successHandler(ctrl.scenario).success(function(){
+ $uibModalInstance.dismiss('cancel');
+ });
}
@@ -208,6 +237,9 @@
function handleModalData(installer){
ctrl.scenario.installers.push(installer)
+ var deferred = $q.defer();
+ deferred.resolve();
+ return deferred.promise;
}
function openInstallerModal(){
@@ -252,8 +284,9 @@
* inputs.
*/
function confirm() {
- ctrl.data.successHandler(ctrl.installer);
- $uibModalInstance.dismiss('cancel');
+ ctrl.data.successHandler(ctrl.installer).success(function(){
+ $uibModalInstance.dismiss('cancel');
+ });
}
@@ -465,9 +498,9 @@
* inputs.
*/
function confirm() {
- ctrl.data.successHandler(ctrl.name,ctrl.data.name);
- $uibModalInstance.dismiss('cancel');
-
+ ctrl.data.successHandler(ctrl.name,ctrl.data.name).success( function() {
+ $uibModalInstance.dismiss('cancel');
+ })
}
/**
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/opnfv_testapi/ui/package.json b/testapi/opnfv_testapi/ui/package.json
index dc99239..2d4eb6e 100644
--- a/testapi/opnfv_testapi/ui/package.json
+++ b/testapi/opnfv_testapi/ui/package.json
@@ -3,6 +3,7 @@
"grunt": "~1.0.1",
"grunt-contrib-connect": "^1.0.2",
"grunt-contrib-copy": "^1.0.0",
+ "grunt-convert": "^0.1.12",
"grunt-karma": "~2.0.0",
"grunt-protractor-coverage": "^0.2.18",
"grunt-protractor-runner": "~5.0.0",
diff --git a/testapi/requirements.txt b/testapi/requirements.txt
index f752a64..9dba746 100644
--- a/testapi/requirements.txt
+++ b/testapi/requirements.txt
@@ -2,11 +2,13 @@
# of appearance. Changing the order has an impact on the overall integration
# process, which may cause wedges in the gate later.
-pbr>=2.0.0,!=2.1.0 # Apache-2.0
-setuptools>=16.0,!=24.0.0,!=34.0.0,!=34.0.1,!=34.0.2,!=34.0.3,!=34.1.0,!=34.1.1,!=34.2.0,!=34.3.0,!=34.3.1,!=34.3.2 # PSF/ZPL
-tornado>=3.1,<=4.3 # Apache-2.0
-epydoc>=0.3.1
-six>=1.9.0 # MIT
-motor # Apache-2.0
+pbr!=2.1.0 # Apache-2.0
+setuptools!=24.0.0,!=34.0.0,!=34.0.1,!=34.0.2,!=34.0.3,!=34.1.0,!=34.1.1,!=34.2.0,!=34.3.0,!=34.3.1,!=34.3.2,!=36.2.0;python_version>='3.5' # PSF/ZPL
+setuptools!=24.0.0,!=34.0.0,!=34.0.1,!=34.0.2,!=34.0.3,!=34.1.0,!=34.1.1,!=34.2.0,!=34.3.0,!=34.3.1,!=34.3.2,!=36.2.0,<45.0.0;python_version<='2.7' # PSF/ZPL
+tornado<=4.3,>=3.1 # Apache-2.0
+epydoc
+six # MIT
+motor # Apache-2.0
python-cas
-requests[security] \ No newline at end of file
+requests[security]!=2.20.0 # Apache-2.0
+futures!=0.17.0;python_version=='2.7' or python_version=='2.6' # PSF
diff --git a/testapi/setup.py b/testapi/setup.py
index f9d95a3..566d844 100644
--- a/testapi/setup.py
+++ b/testapi/setup.py
@@ -1,13 +1,29 @@
-import setuptools
+# Copyright (c) 2013 Hewlett-Packard Development Company, L.P.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
+# implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
-__author__ = 'serena'
+# THIS FILE IS MANAGED BY THE GLOBAL REQUIREMENTS REPO - DO NOT EDIT
+import setuptools
+# In python < 2.7.4, a lazy loading of package `pbr` will break
+# setuptools if some other modules registered functions in `atexit`.
+# solution from: http://bugs.python.org/issue15881#msg170215
try:
import multiprocessing # noqa
except ImportError:
pass
-
setuptools.setup(
setup_requires=['pbr>=2.0.0'],
pbr=True)
diff --git a/testapi/test-requirements.txt b/testapi/test-requirements.txt
index 233f465..67fd8f0 100644
--- a/testapi/test-requirements.txt
+++ b/testapi/test-requirements.txt
@@ -2,9 +2,9 @@
# of appearance. Changing the order has an impact on the overall integration
# process, which may cause wedges in the gate later.
-coverage>=4.0,!=4.4 # Apache-2.0
-mock>=2.0 # BSD
-nose # LGPL
-pytest # MIT
-pytest-cov # MIT
-pytest-mock # MIT
+coverage!=4.4 # Apache-2.0
+mock!=4.0.0,!=4.0.1 # BSD
+nose # LGPL
+pytest # MIT
+pytest-cov
+pytest-mock
diff --git a/testapi/testapi-client/etc/client.creds b/testapi/testapi-client/etc/client.creds
index a082047..ee2a0ab 100644
--- a/testapi/testapi-client/etc/client.creds
+++ b/testapi/testapi-client/etc/client.creds
@@ -1,3 +1,4 @@
export testapi_url=http://localhost:8000/api/v1
export testapi_cas_signin_return=/auth/signin_return
-export testapi_cas_auth_url=https://identity.linuxfoundation.org/user/login?destination=cas/login%3Fservice%3D \ No newline at end of file
+export testapi_cas_auth_url=https://identity.linuxfoundation.org/user/login?destination=cas/login%3Fservice%3D
+export testapi_token=changeme \ No newline at end of file
diff --git a/testapi/testapi-client/setup.cfg b/testapi/testapi-client/setup.cfg
index 72a5a57..ee1ba54 100644
--- a/testapi/testapi-client/setup.cfg
+++ b/testapi/testapi-client/setup.cfg
@@ -26,6 +26,48 @@ 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
+
+ scenario installer create = testapiclient.cli.scenarios:InstallerCreate
+ scenario installer delete = testapiclient.cli.scenarios:InstallerDelete
+ scenario installer put = testapiclient.cli.scenarios:InstallerPut
+
+ scenario version create = testapiclient.cli.scenarios:VersionCreate
+ scenario version delete = testapiclient.cli.scenarios:VersionDelete
+ scenario version put = testapiclient.cli.scenarios:VersionPut
+
+ scenario version owner put = testapiclient.cli.scenarios:VersionOwnerPut
+
+ scenario project create = testapiclient.cli.scenarios:ProjectCreate
+ scenario project delete = testapiclient.cli.scenarios:ProjectDelete
+ scenario project put = testapiclient.cli.scenarios:ProjectPut
+
+ scenario custom create = testapiclient.cli.scenarios:CustomCreate
+ scenario custom delete = testapiclient.cli.scenarios:CustomDelete
+ scenario custom put = testapiclient.cli.scenarios:CustomPut
+
+ scenario trustindicator create = testapiclient.cli.scenarios:TrustIndicatorCreate
+
+ scenario score create = testapiclient.cli.scenarios:ScoreCreate
+
+ deployresult create = testapiclient.cli.deployresults:DeployresultCreate
+ deployresult get = testapiclient.cli.deployresults:DeployresultGet
+ deployresult getone = testapiclient.cli.deployresults:DeployresultGetOne
+
+ result create = testapiclient.cli.results:ResultCreate
+ result get = testapiclient.cli.results:ResultGet
+ result getone = testapiclient.cli.results:ResultGetOne
+
[egg_info]
tag_build =
tag_date = 0
diff --git a/testapi/testapi-client/testapiclient/cli/deployresults.py b/testapi/testapi-client/testapiclient/cli/deployresults.py
new file mode 100644
index 0000000..1ca0bef
--- /dev/null
+++ b/testapi/testapi-client/testapiclient/cli/deployresults.py
@@ -0,0 +1,98 @@
+import json
+
+from testapiclient.utils import command
+from testapiclient.utils import urlparse
+from testapiclient.models import deployresult
+
+
+def deployresults_url():
+ return urlparse.resource_join('deployresults')
+
+
+def deployresult_url(parsed_args):
+ return urlparse.path_join(deployresults_url(), parsed_args.deployresult_id)
+
+
+class DeployresultGet(command.Lister):
+
+ def get_parser(self, prog_name):
+ parser = super(DeployresultGet, self).get_parser(prog_name)
+ parser.add_argument('-build-id',
+ help='Search deployresults using build tag')
+ parser.add_argument('-from',
+ help='Search deployresults using from date')
+ parser.add_argument('-scenario',
+ help='Search deployresults using scenario')
+ parser.add_argument('-period',
+ help='Search deployresults using period')
+ parser.add_argument('-page',
+ help='Search deployresults using page')
+ parser.add_argument('-to',
+ help='Search deployresults using to')
+ parser.add_argument('---version',
+ help='Search deployresults using version')
+ parser.add_argument('-last',
+ help='Search deployresults using last date')
+ parser.add_argument('-pod-name',
+ help='Search deployresults using pod')
+ parser.add_argument('-criteria',
+ help='Search deployresults using version')
+ parser.add_argument('-installer',
+ help='Search deployresults using installer')
+ parser.add_argument('-job-name',
+ help='Search deployresults using project')
+
+ return parser
+
+ def take_action(self, parsed_args):
+ columns = (
+ '_id',
+ 'pod_name',
+ 'version',
+ 'criteria',
+ 'start_date',
+ 'stop_date',
+ 'scenario',
+ 'installer',
+
+ )
+ data = self.app.client_manager.get(
+ urlparse.query_by(deployresults_url(),
+ ['build_id', 'from', 'last',
+ 'scenario', 'period', 'job_name',
+ 'to', 'version',
+ 'criteria', 'installer', 'pod_name', 'page'],
+ parsed_args))
+ return self.format_output(columns, data.get('deployresults', []))
+
+
+class DeployresultGetOne(command.ShowOne):
+
+ def get_parser(self, prog_name):
+ parser = super(DeployresultGetOne, self).get_parser(prog_name)
+ parser.add_argument('deployresult_id',
+ help='Search deployresult by deployresult id')
+ return parser
+
+ def take_action(self, parsed_args):
+ return self.format_output(
+ self.app.client_manager.get(deployresult_url(parsed_args)))
+
+
+class DeployresultCreate(command.ShowOne):
+
+ def get_parser(self, prog_name):
+ parser = super(DeployresultCreate, self).get_parser(prog_name)
+ parser.add_argument('deployresult',
+ type=json.loads,
+ help='Deployresult create request format:\n'
+ '\'{}\''.format(json.dumps(
+ deployresult.DeployResultCreateRequest(
+ ).__dict__
+ )))
+ return parser
+
+ def take_action(self, parsed_args):
+ return self.format_output(
+ self.app.client_manager.post(
+ deployresults_url(), parsed_args.deployresult))
diff --git a/testapi/testapi-client/testapiclient/cli/pods.py b/testapi/testapi-client/testapiclient/cli/pods.py
index 8d0970b..a7706f6 100644
--- a/testapi/testapi-client/testapiclient/cli/pods.py
+++ b/testapi/testapi-client/testapiclient/cli/pods.py
@@ -1,7 +1,9 @@
import json
+from testapiclient.client import pods
from testapiclient.utils import command
from testapiclient.utils import urlparse
+from testapiclient.models import pods as pm
def pods_url():
@@ -60,15 +62,17 @@ class PodCreate(command.ShowOne):
parser.add_argument('pod',
type=json.loads,
help='Pod create request format :\n'
- '\'{"role": "", "name": "", "details": "", '
- '"mode": ""}\',\n role should be either '
+ '\'{}\''.format(json.dumps(
+ pm.PodCreateRequest().__dict__
+ )) +
+ '\n role should be either '
'"community-ci" or "production-ci", and '
'mode should be either "metal" or "virtual.')
return parser
def take_action(self, parsed_args):
- return self.format_output(
- self.app.client_manager.post(pods_url(), parsed_args.pod))
+ client = pods.PodsClient(client_manager=self.app.client_manager)
+ return self.format_output(client.create(parsed_args.pod))
class PodDelete(command.Command):
diff --git a/testapi/testapi-client/testapiclient/cli/projects.py b/testapi/testapi-client/testapiclient/cli/projects.py
index 510acc8..2fa5b5b 100644
--- a/testapi/testapi-client/testapiclient/cli/projects.py
+++ b/testapi/testapi-client/testapiclient/cli/projects.py
@@ -2,6 +2,7 @@ import json
from testapiclient.utils import command
from testapiclient.utils import urlparse
+from testapiclient.models import project
def projects_url():
@@ -51,9 +52,10 @@ class ProjectCreate(command.ShowOne):
parser = super(ProjectCreate, self).get_parser(prog_name)
parser.add_argument('project',
type=json.loads,
- help='Project create request format :{'
- ' "name": (required)"", '
- '"description": (optional)""}')
+ help='Project create request format :\n'
+ '\'{}\''.format(json.dumps(
+ project.ProjectCreateRequest().__dict__
+ )))
return parser
def take_action(self, parsed_args):
@@ -83,9 +85,10 @@ class ProjectPut(command.ShowOne):
help='Update project by name')
parser.add_argument('project',
type=json.loads,
- help='Project Update request format :{'
- '"name": (required)"", '
- '"description": (optional)""}')
+ help='Project Update request format :\n'
+ '\'{}\''.format(json.dumps(
+ project.ProjectCreateRequest().__dict__
+ )))
return parser
def take_action(self, parsed_args):
diff --git a/testapi/testapi-client/testapiclient/cli/results.py b/testapi/testapi-client/testapiclient/cli/results.py
new file mode 100644
index 0000000..5500501
--- /dev/null
+++ b/testapi/testapi-client/testapiclient/cli/results.py
@@ -0,0 +1,97 @@
+import json
+
+from testapiclient.utils import command
+from testapiclient.utils import urlparse
+from testapiclient.models import result
+
+
+def results_url():
+ return urlparse.resource_join('results')
+
+
+def result_url(parsed_args):
+ return urlparse.path_join(results_url(), parsed_args.result_id)
+
+
+class ResultGet(command.Lister):
+
+ def get_parser(self, prog_name):
+ parser = super(ResultGet, self).get_parser(prog_name)
+ parser.add_argument('-case',
+ help='Search results using tesetcase')
+ parser.add_argument('-build-tag',
+ help='Search results using build tag')
+ parser.add_argument('-from',
+ help='Search results using from date')
+ parser.add_argument('-last',
+ help='Search results using last date')
+ parser.add_argument('-scenario',
+ help='Search results using scenario')
+ parser.add_argument('-period',
+ help='Search results using period')
+ parser.add_argument('-project',
+ help='Search results using project')
+ parser.add_argument('-to',
+ help='Search results using to')
+ parser.add_argument('---version',
+ help='Search results using version')
+ parser.add_argument('-criteria',
+ help='Search results using version')
+ parser.add_argument('-installer',
+ help='Search results using installer')
+ parser.add_argument('-pod',
+ help='Search results using pod')
+ parser.add_argument('-page',
+ help='Search results using page')
+ return parser
+
+ def take_action(self, parsed_args):
+ columns = (
+ '_id',
+ 'pod_name',
+ 'project_name',
+ 'case_name',
+ 'installer',
+ 'version',
+ 'scenario',
+ 'criteria',
+ 'start_date'
+ )
+ data = self.app.client_manager.get(
+ urlparse.query_by(results_url(),
+ ['case', 'build_tag', 'from', 'last',
+ 'scenario', 'period', 'project',
+ 'to', 'version',
+ 'criteria', 'installer', 'pod', 'page'],
+ parsed_args))
+ return self.format_output(columns, data.get('results', []))
+
+
+class ResultGetOne(command.ShowOne):
+
+ def get_parser(self, prog_name):
+ parser = super(ResultGetOne, self).get_parser(prog_name)
+ parser.add_argument('result_id',
+ help='Search result by result id')
+ return parser
+
+ def take_action(self, parsed_args):
+ return self.format_output(
+ self.app.client_manager.get(result_url(parsed_args)))
+
+
+class ResultCreate(command.ShowOne):
+
+ def get_parser(self, prog_name):
+ parser = super(ResultCreate, self).get_parser(prog_name)
+ parser.add_argument('result',
+ type=json.loads,
+ help='Result create request format:\n'
+ '\'{}\''.format(json.dumps(
+ result.ResultCreateRequest().__dict__)))
+ return parser
+
+ def take_action(self, parsed_args):
+ return self.format_output(
+ self.app.client_manager.post(
+ results_url(), parsed_args.result))
diff --git a/testapi/testapi-client/testapiclient/cli/scenarios.py b/testapi/testapi-client/testapiclient/cli/scenarios.py
new file mode 100644
index 0000000..197ee0c
--- /dev/null
+++ b/testapi/testapi-client/testapiclient/cli/scenarios.py
@@ -0,0 +1,603 @@
+import json
+
+from testapiclient.utils import command
+from testapiclient.utils import urlparse
+from testapiclient.models import scenario
+
+
+def scenarios_url():
+ return urlparse.resource_join('scenarios')
+
+
+def scenario_url(parsed_args):
+ return urlparse.path_join(scenarios_url(), parsed_args.name)
+
+
+def resources_url(name, resuorce):
+ return urlparse.resource_join('scenarios', name, resuorce)
+
+
+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'
+ '\'{}\''.format(json.dumps(
+ scenario.ScenarioCreateRequest(
+ ).__dict__
+ )) +
+ '\n Intaller create request format :\n'
+ '\'{}\''.format(json.dumps(
+ scenario.ScenarioInstallerCreateRequest(
+ ).__dict__
+ )) +
+ '\n Version create request format :\n'
+ '\'{}\''.format(json.dumps(
+ scenario.ScenarioVersionCreateRequest(
+ ).__dict__
+ )) +
+ '\n Project create request format :\n'
+ '\'{}\''.format(json.dumps(
+ scenario.ScenarioProjectCreateRequest(
+ ).__dict__
+ )) +
+ '\n Custom create request format :\n'
+ '\'["asf","saf"]\',\n'
+ '\n Score create request format :\n'
+ '\'{}\''.format(json.dumps(
+ scenario.ScenarioScoreCreateRequest(
+ ).__dict__
+ )) +
+ '\nTrustIndicator create request format:\n'
+ '\'{}\''.format(json.dumps(
+ scenario.ScenarioTICreateRequest(
+ ).__dict__
+ )))
+ 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' +
+ '\'{}\''.format(json.dumps(
+ scenario.ScenarioCreateRequest(
+ ).__dict__
+ )) +
+ '\n Intaller create request format :\n'
+ '\'{}\''.format(json.dumps(
+ scenario.ScenarioInstallerCreateRequest(
+ ).__dict__
+ )) +
+ '\n Version create request format :\n'
+ '\'{}\''.format(json.dumps(
+ scenario.ScenarioVersionCreateRequest(
+ ).__dict__
+ )) +
+ '\n Project create request format :\n'
+ '\'{}\''.format(json.dumps(
+ scenario.ScenarioProjectCreateRequest(
+ ).__dict__
+ )) +
+ '\n Custom create request format :\n'
+ '\'["asf","saf"]\',\n'
+ '\n Score create request format :\n'
+ '\'{}\''.format(json.dumps(
+ scenario.ScenarioScoreCreateRequest(
+ ).__dict__
+ )) +
+ '\nTrustIndicator create request format:\n'
+ '\'{}\''.format(json.dumps(
+ scenario.ScenarioTICreateRequest(
+ ).__dict__
+ )))
+ return parser
+
+ def take_action(self, parsed_args):
+ return self.format_output(
+ self.app.client_manager.put(
+ scenario_url(parsed_args), parsed_args.scenario))
+
+
+class InstallerCreate(command.Command):
+
+ def get_parser(self, prog_name):
+ parser = super(InstallerCreate, self).get_parser(prog_name)
+ parser.add_argument('--scenario-name',
+ required=True,
+ help='Create installer under scenario name')
+ parser.add_argument('installer',
+ type=json.loads,
+ help='Intaller create request format :\n'
+ '\'{}\''.format(json.dumps(
+ scenario.ScenarioInstallerCreateRequest(
+ ).__dict__
+ )))
+ return parser
+
+ def take_action(self, parsed_args):
+ return self.app.client_manager.post(
+ resources_url(
+ parsed_args.scenario_name,
+ 'installers'), parsed_args.installer)
+
+
+class InstallerDelete(command.Command):
+
+ def get_parser(self, prog_name):
+ parser = super(InstallerDelete, self).get_parser(prog_name)
+ parser.add_argument('--scenario-name',
+ required=True,
+ type=str,
+ help='Delete installer by scenario name')
+ parser.add_argument('name',
+ nargs='+',
+ help='Delete installer by name')
+ return parser
+
+ def take_action(self, parsed_args):
+ return self.app.client_manager.delete(
+ resources_url(
+ parsed_args.scenario_name,
+ 'installers'), parsed_args.name)
+
+
+class InstallerPut(command.Command):
+
+ def get_parser(self, prog_name):
+ parser = super(InstallerPut, self).get_parser(prog_name)
+ parser.add_argument('--scenario-name',
+ type=str,
+ required=True,
+ help='Update installer by scenario name')
+ parser.add_argument('installer',
+ type=json.loads,
+ help='Intaller create request format :\n'
+ '\'{}\''.format(json.dumps(
+ scenario.ScenarioInstallerCreateRequest(
+ ).__dict__
+ )))
+ return parser
+
+ def take_action(self, parsed_args):
+ return self.app.client_manager.put(
+ resources_url(
+ parsed_args.scenario_name,
+ 'installers'), parsed_args.installer)
+
+
+class VersionCreate(command.Command):
+
+ def get_parser(self, prog_name):
+ parser = super(VersionCreate, self).get_parser(prog_name)
+ parser.add_argument('--scenario-name',
+ required=True,
+ help='Create version under scenario name')
+ parser.add_argument('--installer',
+ required=True,
+ help='Create version under scenario name')
+ parser.add_argument('version',
+ type=json.loads,
+ help='version create request format :\n'
+ '\'{}\''.format(json.dumps(
+ scenario.ScenarioVersionCreateRequest(
+ ).__dict__
+ )))
+ return parser
+
+ def take_action(self, parsed_args):
+ return self.app.client_manager.post(
+ urlparse.query_by(
+ resources_url(parsed_args.scenario_name, 'versions'),
+ 'installer',
+ parsed_args), parsed_args.version)
+
+
+class VersionDelete(command.Command):
+
+ def get_parser(self, prog_name):
+ parser = super(VersionDelete, self).get_parser(prog_name)
+ parser.add_argument('--scenario-name',
+ required=True,
+ type=str,
+ help='Delete version by scenario name')
+ parser.add_argument('--installer',
+ required=True,
+ help='Create version under scenario name')
+ parser.add_argument('name',
+ nargs='+',
+ help='Delete version by name')
+ return parser
+
+ def take_action(self, parsed_args):
+ return self.app.client_manager.delete(
+ urlparse.query_by(
+ resources_url(parsed_args.scenario_name, 'versions'),
+ 'installer',
+ parsed_args), parsed_args.name)
+
+
+class VersionPut(command.Command):
+
+ def get_parser(self, prog_name):
+ parser = super(VersionPut, self).get_parser(prog_name)
+ parser.add_argument('--scenario-name',
+ type=str,
+ required=True,
+ help='Update installer by scenario name')
+ parser.add_argument('--installer',
+ required=True,
+ help='Update version under installer name')
+ parser.add_argument('version',
+ type=json.loads,
+ help='version update request format :\n'
+ '\'{}\''.format(json.dumps(
+ scenario.ScenarioVersionCreateRequest(
+ ).__dict__
+ )))
+ return parser
+
+ def take_action(self, parsed_args):
+ return self.app.client_manager.put(
+ urlparse.query_by(
+ resources_url(parsed_args.scenario_name, 'versions'),
+ 'installer',
+ parsed_args), parsed_args.version)
+
+
+class VersionOwnerPut(command.Command):
+
+ def get_parser(self, prog_name):
+ parser = super(VersionOwnerPut, self).get_parser(prog_name)
+ parser.add_argument('--scenario-name',
+ type=str,
+ required=True,
+ help='Update version by scenario name')
+ parser.add_argument('--installer',
+ required=True,
+ help='Update version under scenario name')
+ parser.add_argument('--version',
+ required=True,
+ help='Update version under scenario name')
+ parser.add_argument('owner',
+ type=json.loads,
+ help='Intaller create request format :\n'
+ '\'{"owner": ""}\',\n')
+ return parser
+
+ def take_action(self, parsed_args):
+ return self.app.client_manager.put(
+ urlparse.query_by(
+ resources_url(parsed_args.scenario_name, 'owner'),
+ ['installer', 'version'],
+ parsed_args), parsed_args.owner)
+
+
+class ProjectCreate(command.Command):
+
+ def get_parser(self, prog_name):
+ parser = super(ProjectCreate, self).get_parser(prog_name)
+ parser.add_argument('--scenario-name',
+ type=str,
+ required=True,
+ help='Create project by scenario name')
+ parser.add_argument('--installer',
+ required=True,
+ help='Create project under installer name')
+ parser.add_argument('--version',
+ required=True,
+ help='Create project under version name')
+ parser.add_argument('project',
+ type=json.loads,
+ help='Project create request format :\n'
+ '\'{}\''.format(json.dumps(
+ scenario.ScenarioProjectCreateRequest(
+ ).__dict__
+ )))
+ return parser
+
+ def take_action(self, parsed_args):
+ return self.app.client_manager.post(
+ urlparse.query_by(
+ resources_url(parsed_args.scenario_name, 'projects'),
+ ['installer', 'version'],
+ parsed_args), parsed_args.project)
+
+
+class ProjectDelete(command.Command):
+
+ def get_parser(self, prog_name):
+ parser = super(ProjectDelete, self).get_parser(prog_name)
+ parser.add_argument('--scenario-name',
+ required=True,
+ type=str,
+ help='Delete projects by scenario name')
+ parser.add_argument('--installer',
+ required=True,
+ help='Delete projects under installer name')
+ parser.add_argument('--version',
+ required=True,
+ help='Delete projects under version name')
+ parser.add_argument('name',
+ nargs='+',
+ help='Delete projects by name')
+ return parser
+
+ def take_action(self, parsed_args):
+ return self.app.client_manager.delete(
+ urlparse.query_by(
+ resources_url(parsed_args.scenario_name, 'projects'),
+ ['installer', 'version'],
+ parsed_args), parsed_args.name)
+
+
+class ProjectPut(command.Command):
+
+ def get_parser(self, prog_name):
+ parser = super(ProjectPut, self).get_parser(prog_name)
+ parser.add_argument('--scenario-name',
+ type=str,
+ required=True,
+ help='Update project by scenario name')
+ parser.add_argument('--installer',
+ required=True,
+ help='Update project under installer name')
+ parser.add_argument('--version',
+ required=True,
+ help='Update project under version name')
+ parser.add_argument('project',
+ type=json.loads,
+ help='Project update request format :\n'
+ '\'{}\''.format(json.dumps(
+ scenario.ScenarioProjectCreateRequest(
+ ).__dict__
+ )))
+ return parser
+
+ def take_action(self, parsed_args):
+ return self.app.client_manager.put(
+ urlparse.query_by(
+ resources_url(parsed_args.scenario_name, 'projects'),
+ ['installer', 'version'],
+ parsed_args), parsed_args.project)
+
+
+class CustomCreate(command.Command):
+
+ def get_parser(self, prog_name):
+ parser = super(CustomCreate, self).get_parser(prog_name)
+ parser.add_argument('--scenario-name',
+ type=str,
+ required=True,
+ help='Create custom by scenario name')
+ parser.add_argument('--installer',
+ required=True,
+ help='Create custom under installer name')
+ parser.add_argument('--version',
+ required=True,
+ help='Create custom under version name')
+ parser.add_argument('--project',
+ required=True,
+ help='Create custom under project name')
+ parser.add_argument('custom',
+ nargs='+',
+ help='Space sperated strings')
+ return parser
+
+ def take_action(self, parsed_args):
+ return self.app.client_manager.post(
+ urlparse.query_by(
+ resources_url(
+ parsed_args.scenario_name,
+ 'customs'),
+ ['installer', 'version', 'project'],
+ parsed_args),
+ parsed_args.custom)
+
+
+class CustomDelete(command.Command):
+
+ def get_parser(self, prog_name):
+ parser = super(CustomDelete, self).get_parser(prog_name)
+ parser.add_argument('--scenario-name',
+ required=True,
+ type=str,
+ help='Delete custom by scenario name')
+ parser.add_argument('--installer',
+ required=True,
+ help='Create custom under scenario name')
+ parser.add_argument('--version',
+ required=True,
+ help='Create custom under scenario name')
+ parser.add_argument('--project',
+ required=True,
+ help='Create custom under scenario name')
+ parser.add_argument('name',
+ nargs='+',
+ help='Delete custom by name')
+ return parser
+
+ def take_action(self, parsed_args):
+ return self.app.client_manager.delete(
+ urlparse.query_by(
+ resources_url(
+ parsed_args.scenario_name,
+ 'customs'),
+ ['installer', 'version', 'project'],
+ parsed_args),
+ parsed_args.name)
+
+
+class CustomPut(command.Command):
+
+ def get_parser(self, prog_name):
+ parser = super(CustomPut, self).get_parser(prog_name)
+ parser.add_argument('--scenario-name',
+ type=str,
+ required=True,
+ help='Update custom by scenario name')
+ parser.add_argument('--installer',
+ required=True,
+ help='Update custom under installer name')
+ parser.add_argument('--version',
+ required=True,
+ help='Update custom under version name')
+ parser.add_argument('--project',
+ required=True,
+ help='Update custom under project name')
+ parser.add_argument('custom',
+ nargs='+',
+ help='space sperated strings')
+ return parser
+
+ def take_action(self, parsed_args):
+ return self.app.client_manager.put(
+ urlparse.query_by(
+ resources_url(
+ parsed_args.scenario_name,
+ 'customs'),
+ ['installer', 'version', 'project'],
+ parsed_args),
+ parsed_args.custom)
+
+
+class TrustIndicatorCreate(command.Command):
+
+ def get_parser(self, prog_name):
+ parser = super(TrustIndicatorCreate, self).get_parser(prog_name)
+ parser.add_argument('--scenario-name',
+ type=str,
+ required=True,
+ help='Create trust indicator by scenario name')
+ parser.add_argument('--installer',
+ required=True,
+ help='Create trustindicator under installer name')
+ parser.add_argument('--version',
+ required=True,
+ help='Create trust indicator under version name')
+ parser.add_argument('--project',
+ required=True,
+ help='Create trust indicator under project name')
+ parser.add_argument('trust_indicator',
+ type=json.loads,
+ help='trust indicator create request format :\n'
+ '\'{}\''.format(json.dumps(
+ scenario.ScenarioTICreateRequest(
+ ).__dict__
+ )))
+ return parser
+
+ def take_action(self, parsed_args):
+ print parsed_args
+ return self.app.client_manager.post(
+ urlparse.query_by(
+ resources_url(
+ parsed_args.scenario_name,
+ 'trust_indicators'),
+ ['installer', 'version', 'project'],
+ parsed_args),
+ parsed_args.trust_indicator)
+
+
+class ScoreCreate(command.Command):
+
+ def get_parser(self, prog_name):
+ parser = super(ScoreCreate, self).get_parser(prog_name)
+ parser.add_argument('--scenario-name',
+ type=str,
+ required=True,
+ help='Create score by scenario name')
+ parser.add_argument('--installer',
+ required=True,
+ help='Create score under installer name')
+ parser.add_argument('--version',
+ required=True,
+ help='Create score under version name')
+ parser.add_argument('--project',
+ required=True,
+ help='Create score under project name')
+ parser.add_argument('score',
+ type=json.loads,
+ help='score create request format :\n'
+ '\'{}\''.format(json.dumps(
+ scenario.ScenarioScoreCreateRequest(
+ ).__dict__
+ )))
+ return parser
+
+ def take_action(self, parsed_args):
+ return self.app.client_manager.post(
+ urlparse.query_by(
+ resources_url(
+ parsed_args.scenario_name,
+ 'scores'),
+ ['installer', 'version', 'project'],
+ parsed_args),
+ parsed_args.score)
diff --git a/testapi/testapi-client/testapiclient/cli/testcases.py b/testapi/testapi-client/testapiclient/cli/testcases.py
new file mode 100644
index 0000000..3052c18
--- /dev/null
+++ b/testapi/testapi-client/testapiclient/cli/testcases.py
@@ -0,0 +1,114 @@
+import json
+
+from testapiclient.utils import command
+from testapiclient.utils import urlparse
+from testapiclient.models import testcase
+
+
+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'
+ '\'{}\''.format(json.dumps(
+ testcase.TestCaseCreateRequest().__dict__
+ )))
+ 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'
+ '\'{}\''.format(json.dumps(
+ testcase.TestCaseCreateRequest().__dict__
+ )))
+ 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/client/__init__.py b/testapi/testapi-client/testapiclient/client/__init__.py
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/testapi/testapi-client/testapiclient/client/__init__.py
diff --git a/testapi/testapi-client/testapiclient/client/base.py b/testapi/testapi-client/testapiclient/client/base.py
new file mode 100644
index 0000000..c45c9b7
--- /dev/null
+++ b/testapi/testapi-client/testapiclient/client/base.py
@@ -0,0 +1,23 @@
+from testapiclient.utils import clientmanager
+from testapiclient.utils import urlparse
+
+
+class AuthOption(object):
+ def __init__(self, user=None, password=None):
+ self.u = user
+ self.p = password
+
+
+class Client(object):
+
+ resource = ''
+
+ def __init__(self, user=None, password=None, client_manager=None):
+ self.url = urlparse.resource_join(self.resource)
+ if client_manager:
+ self.clientmanager = client_manager
+ else:
+ self.clientmanager = clientmanager.ClientManager(
+ AuthOption(user, password))
+ if self.clientmanager.auth_required:
+ self.clientmanager.auth()
diff --git a/testapi/testapi-client/testapiclient/client/deploy_results.py b/testapi/testapi-client/testapiclient/client/deploy_results.py
new file mode 100644
index 0000000..b0724b0
--- /dev/null
+++ b/testapi/testapi-client/testapiclient/client/deploy_results.py
@@ -0,0 +1,28 @@
+import json
+
+from testapiclient.client import base
+from testapiclient.utils import urlparse
+
+
+class DeployResultsClient(base.Client):
+ resource = 'deployresults'
+
+ def __init__(self, **kwargs):
+ super(DeployResultsClient, self).__init__(**kwargs)
+
+ def create(self, testcase_req):
+ return self.clientmanager.post(self.url, testcase_req)
+
+ def get(self, **queries):
+ if queries:
+ return json.dumps(
+ self.clientmanager.get(
+ urlparse.query_join(self.url, **queries))['deployresults'])
+ else:
+ return json.dumps(
+ self.clientmanager.get(self.url)['deployresults'])
+
+ def get_one(self, id):
+ return json.dumps(
+ self.clientmanager.get(
+ urlparse.path_join(self.url, id)))
diff --git a/testapi/testapi-client/testapiclient/client/pods.py b/testapi/testapi-client/testapiclient/client/pods.py
new file mode 100644
index 0000000..d08114f
--- /dev/null
+++ b/testapi/testapi-client/testapiclient/client/pods.py
@@ -0,0 +1,31 @@
+import json
+
+from testapiclient.client import base
+from testapiclient.utils import urlparse
+
+
+class PodsClient(base.Client):
+ resource = 'pods'
+
+ def __init__(self, **kwargs):
+ super(PodsClient, self).__init__(**kwargs)
+
+ def create(self, pod_req):
+ return self.clientmanager.post(self.url, pod_req)
+
+ def get(self, **queries):
+ if queries:
+ return json.dumps(
+ self.clientmanager.get(
+ urlparse.query_join(self.url, **queries))['pods'])
+ else:
+ return json.dumps(
+ self.clientmanager.get(self.url)['pods'])
+
+ def get_one(self, name):
+ return json.dumps(self.clientmanager.get(
+ urlparse.path_join(self.url, name)))
+
+ def delete(self, name):
+ return self.clientmanager.delete(
+ urlparse.path_join(self.url, name))
diff --git a/testapi/testapi-client/testapiclient/client/projects.py b/testapi/testapi-client/testapiclient/client/projects.py
new file mode 100644
index 0000000..63d00fe
--- /dev/null
+++ b/testapi/testapi-client/testapiclient/client/projects.py
@@ -0,0 +1,35 @@
+import json
+
+from testapiclient.client import base
+from testapiclient.utils import urlparse
+
+
+class ProjectsClient(base.Client):
+ resource = 'projects'
+
+ def __init__(self, **kwargs):
+ super(ProjectsClient, self).__init__(**kwargs)
+
+ def create(self, project_req):
+ return self.clientmanager.post(self.url, project_req)
+
+ def get(self, **queries):
+ if queries:
+ return json.dumps(
+ self.clientmanager.get(
+ urlparse.query_join(self.url, **queries))['projects'])
+ else:
+ return json.dumps(
+ self.clientmanager.get(self.url)['projects'])
+
+ def get_one(self, name):
+ return json.dumps(self.clientmanager.get(
+ urlparse.path_join(self.url, name)))
+
+ def delete(self, name):
+ return self.clientmanager.delete(
+ urlparse.path_join(self.url, name))
+
+ def update(self, name, project_req):
+ return self.clientmanager.put(
+ urlparse.path_join(self.url, name), project_req)
diff --git a/testapi/testapi-client/testapiclient/client/results.py b/testapi/testapi-client/testapiclient/client/results.py
new file mode 100644
index 0000000..7d9ad0e
--- /dev/null
+++ b/testapi/testapi-client/testapiclient/client/results.py
@@ -0,0 +1,28 @@
+import json
+
+from testapiclient.client import base
+from testapiclient.utils import urlparse
+
+
+class ResultsClient(base.Client):
+ resource = 'results'
+
+ def __init__(self, **kwargs):
+ super(ResultsClient, self).__init__(**kwargs)
+
+ def create(self, testcase_req):
+ return self.clientmanager.post(self.url, testcase_req)
+
+ def get(self, **queries):
+ if queries:
+ return json.dumps(
+ self.clientmanager.get(
+ urlparse.query_join(self.url, **queries))['results'])
+ else:
+ return json.dumps(
+ self.clientmanager.get(self.url)['results'])
+
+ def get_one(self, id):
+ return json.dumps(
+ self.clientmanager.get(
+ urlparse.path_join(self.url, id)))
diff --git a/testapi/testapi-client/testapiclient/client/scenarios.py b/testapi/testapi-client/testapiclient/client/scenarios.py
new file mode 100644
index 0000000..e5ce2f1
--- /dev/null
+++ b/testapi/testapi-client/testapiclient/client/scenarios.py
@@ -0,0 +1,177 @@
+import json
+
+from testapiclient.client import base
+from testapiclient.utils import urlparse
+
+
+class ScenariosClient(base.Client):
+ resource = 'scenarios'
+
+ def __init__(self, **kwargs):
+ super(ScenariosClient, self).__init__(**kwargs)
+
+ def create(self, scenario_req):
+ return self.clientmanager.post(self.url, scenario_req)
+
+ def get(self, **queries):
+ if queries:
+ return json.dumps(
+ self.clientmanager.get(
+ urlparse.query_join(self.url, **queries))['scenarios'])
+ else:
+ return json.dumps(
+ self.clientmanager.get(self.url)['scenarios'])
+
+ def get_one(self, scenario_name):
+ return json.dumps(
+ self.clientmanager.get(
+ urlparse.path_join(
+ self.url, scenario_name)))
+
+ def delete(self, scenario_name):
+ return self.clientmanager.delete(
+ urlparse.path_join(
+ self.url, scenario_name))
+
+ def update(self, scenario_name, scenario_req):
+ return self.clientmanager.put(
+ urlparse.path_join(
+ self.url, scenario_name), scenario_req)
+
+
+class InstallersClient(base.Client):
+ resource = 'scenarios/{}/installers'
+
+ def __init__(self, **kwargs):
+ super(InstallersClient, self).__init__(**kwargs)
+
+ def delete(self, scenario_name, name):
+ return self.clientmanager.delete(
+ self.url.format(scenario_name), [name])
+
+ def update(self, scenario_name, installer_req):
+ return self.clientmanager.put(
+ self.url.format(scenario_name), installer_req)
+
+ def create(self, scenario_name, installer_req):
+ return self.clientmanager.post(
+ self.url.format(scenario_name), installer_req)
+
+
+class VersionsClient(base.Client):
+ resource = 'scenarios/{}/versions'
+
+ def __init__(self, **kwargs):
+ super(VersionsClient, self).__init__(**kwargs)
+
+ def delete(self, scenario_name, installer, name):
+ queries = {'installer': installer}
+ return self.clientmanager.delete(
+ urlparse.query_join(
+ self.url.format(scenario_name), **queries), name)
+
+ def update(self, scenario_name, installer, version_req):
+ queries = {'installer': installer}
+ return self.clientmanager.put(
+ urlparse.query_join(
+ self.url.format(scenario_name), **queries), version_req)
+
+ def create(self, scenario_name, installer, version_req):
+ queries = {'installer': installer}
+ return self.clientmanager.post(
+ urlparse.query_join(
+ self.url.format(scenario_name), **queries), version_req)
+
+
+class VersionsOwnerClient(base.Client):
+ resource = 'scenarios/{}/owner'
+
+ def __init__(self, **kwargs):
+ super(VersionsOwnerClient, self).__init__(**kwargs)
+
+ def update(self, scenario_name, installer, version, owner):
+ queries = {'installer': installer, 'version': version}
+ return self.clientmanager.put(
+ urlparse.query_join(
+ self.url.format(scenario_name), **queries), owner)
+
+
+class ProjectsClient(base.Client):
+ resource = 'scenarios/{}/projects'
+
+ def __init__(self, **kwargs):
+ super(ProjectsClient, self).__init__(**kwargs)
+
+ def delete(self, scenario_name, installer, version, name):
+ queries = {'installer': installer, 'version': version}
+ return self.clientmanager.delete(
+ urlparse.query_join(
+ self.url.format(scenario_name), **queries), name)
+
+ def update(self, scenario_name, installer, version, project_req):
+ queries = {'installer': installer, 'version': version}
+ return self.clientmanager.put(
+ urlparse.query_join(
+ self.url.format(scenario_name), **queries), project_req)
+
+ def create(self, scenario_name, installer, version, project_req):
+ queries = {'installer': installer, 'version': version}
+ return self.clientmanager.post(
+ urlparse.query_join(
+ self.url.format(scenario_name), **queries), project_req)
+
+
+class TrustIndicatorsClient(base.Client):
+ resource = 'scenarios/{}/trust_indicators'
+
+ def __init__(self, **kwargs):
+ super(TrustIndicatorsClient, self).__init__(**kwargs)
+
+ def create(self, scenario_name, installer, version, project, trust_in_req):
+ queries = {
+ 'installer': installer, 'version': version, 'project': project}
+ return self.clientmanager.post(
+ urlparse.query_join(
+ self.url.format(scenario_name), **queries), trust_in_req)
+
+
+class ScoresClient(base.Client):
+ resource = 'scenarios/{}/scores'
+
+ def __init__(self, **kwargs):
+ super(ScoresClient, self).__init__(**kwargs)
+
+ def create(self, scenario_name, installer, version, project, scores_req):
+ queries = {
+ 'installer': installer, 'version': version, 'project': project}
+ return self.clientmanager.post(
+ urlparse.query_join(
+ self.url.format(scenario_name), **queries), scores_req)
+
+
+class CustomsClient(base.Client):
+ resource = 'scenarios/{}/customs'
+
+ def __init__(self, **kwargs):
+ super(CustomsClient, self).__init__(**kwargs)
+
+ def delete(self, scenario_name, installer, version, project, customs):
+ queries = {
+ 'installer': installer, 'version': version, 'project': project}
+ return self.clientmanager.delete(
+ urlparse.query_join(
+ self.url.format(scenario_name), **queries), customs)
+
+ def update(self, scenario_name, installer, version, project, customs):
+ queries = {
+ 'installer': installer, 'version': version, 'project': project}
+ return self.clientmanager.put(
+ urlparse.query_join(
+ self.url.format(scenario_name), **queries), customs)
+
+ def create(self, scenario_name, installer, version, project, customs):
+ queries = {
+ 'installer': installer, 'version': version, 'project': project}
+ return self.clientmanager.post(
+ urlparse.query_join(
+ self.url.format(scenario_name), **queries), customs)
diff --git a/testapi/testapi-client/testapiclient/client/testcases.py b/testapi/testapi-client/testapiclient/client/testcases.py
new file mode 100644
index 0000000..bb2b6d3
--- /dev/null
+++ b/testapi/testapi-client/testapiclient/client/testcases.py
@@ -0,0 +1,36 @@
+import json
+
+from testapiclient.client import base
+from testapiclient.utils import urlparse
+
+
+class TestcasesClient(base.Client):
+ resource = 'projects/{}/cases'
+
+ def __init__(self, **kwargs):
+ super(TestcasesClient, self).__init__(**kwargs)
+
+ def create(self, project_name, testcase_req):
+ return self.clientmanager.post(
+ self.url.format(project_name), testcase_req)
+
+ def get(self, project_name):
+ return json.dumps(
+ self.clientmanager.get(
+ self.url.format(project_name))['testcases'])
+
+ def get_one(self, project_name, name):
+ return json.dumps(
+ self.clientmanager.get(
+ urlparse.path_join(
+ self.url.format(project_name), name)))
+
+ def delete(self, project_name, name):
+ return self.clientmanager.delete(
+ urlparse.path_join(
+ self.url.format(project_name), name))
+
+ def update(self, project_name, name, testcase_req):
+ return self.clientmanager.put(
+ urlparse.path_join(
+ self.url.format(project_name), name), testcase_req)
diff --git a/testapi/testapi-client/testapiclient/models/__init__.py b/testapi/testapi-client/testapiclient/models/__init__.py
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/testapi/testapi-client/testapiclient/models/__init__.py
diff --git a/testapi/testapi-client/testapiclient/models/deployresult.py b/testapi/testapi-client/testapiclient/models/deployresult.py
new file mode 100644
index 0000000..5c13966
--- /dev/null
+++ b/testapi/testapi-client/testapiclient/models/deployresult.py
@@ -0,0 +1,17 @@
+class DeployResultCreateRequest():
+ def __init__(
+ self, build_id='', scenario='', stop_date='', start_date='',
+ upstream_job_name='', version='', pod_name='', criteria='',
+ installer='', upstream_build_id='', job_name='', details=''):
+ self.build_id = build_id
+ self.scenario = scenario
+ self.stop_date = stop_date
+ self.start_date = start_date
+ self.upstream_job_name = upstream_job_name
+ self.version = version
+ self.pod_name = pod_name
+ self.criteria = criteria
+ self.installer = installer
+ self.upstream_build_id = upstream_build_id
+ self.job_name = job_name
+ self.details = details
diff --git a/testapi/testapi-client/testapiclient/models/pods.py b/testapi/testapi-client/testapiclient/models/pods.py
new file mode 100644
index 0000000..4fa42e7
--- /dev/null
+++ b/testapi/testapi-client/testapiclient/models/pods.py
@@ -0,0 +1,6 @@
+class PodCreateRequest(object):
+ def __init__(self, name='', mode='', details='', role=''):
+ self.name = name
+ self.mode = mode
+ self.details = details
+ self.role = role
diff --git a/testapi/testapi-client/testapiclient/models/project.py b/testapi/testapi-client/testapiclient/models/project.py
new file mode 100644
index 0000000..fc85588
--- /dev/null
+++ b/testapi/testapi-client/testapiclient/models/project.py
@@ -0,0 +1,4 @@
+class ProjectCreateRequest():
+ def __init__(self, name='', description=''):
+ self.description = description
+ self.name = name
diff --git a/testapi/testapi-client/testapiclient/models/result.py b/testapi/testapi-client/testapiclient/models/result.py
new file mode 100644
index 0000000..766c03a
--- /dev/null
+++ b/testapi/testapi-client/testapiclient/models/result.py
@@ -0,0 +1,16 @@
+class ResultCreateRequest():
+ def __init__(
+ self, project_name='', scenario='', case_name='', pod_name='',
+ installer='', version='', stop_date='', build_tag='', criteria='',
+ start_date='', details=''):
+ self.project_name = project_name
+ self.scenario = scenario
+ self.case_name = case_name
+ self.pod_name = pod_name
+ self.installer = installer
+ self.version = version
+ self.stop_date = stop_date
+ self.build_tag = build_tag
+ self.criteria = criteria
+ self.start_date = start_date
+ self.details = details
diff --git a/testapi/testapi-client/testapiclient/models/scenario.py b/testapi/testapi-client/testapiclient/models/scenario.py
new file mode 100644
index 0000000..f4f0f40
--- /dev/null
+++ b/testapi/testapi-client/testapiclient/models/scenario.py
@@ -0,0 +1,37 @@
+class ScenarioCreateRequest:
+ def __init__(self, name='', installers=[]):
+ self.name = name
+ self.installers = installers
+
+
+class ScenarioInstallerCreateRequest:
+ def __init__(self, installer='', versions=[]):
+ self.installer = installer
+ self.versions = versions
+
+
+class ScenarioVersionCreateRequest:
+ def __init__(self, version='', owner='', projects=[]):
+ self.version = version
+ self.owner = owner
+ self.projects = projects
+
+
+class ScenarioProjectCreateRequest:
+ def __init__(self, project='', scores=[], trust_indicators=[], customs=[]):
+ self.project = project
+ self.scores = scores
+ self.trust_indicators = trust_indicators
+ self.customs = customs
+
+
+class ScenarioScoreCreateRequest:
+ def __init__(self, score='', date=''):
+ self.score = score
+ self.date = date
+
+
+class ScenarioTICreateRequest:
+ def __init__(self, status='', date=''):
+ self.status = status
+ self.date = date
diff --git a/testapi/testapi-client/testapiclient/models/testcase.py b/testapi/testapi-client/testapiclient/models/testcase.py
new file mode 100644
index 0000000..70d5d78
--- /dev/null
+++ b/testapi/testapi-client/testapiclient/models/testcase.py
@@ -0,0 +1,20 @@
+class TestCaseCreateRequest():
+ def __init__(
+ self, run='', name='', ci_loop='', tags='', url='',
+ blocking='', domains='', dependencies='', version='',
+ criteria='', tier='', trust='', catalog_description='',
+ description=''):
+ self.run = run
+ self.name = name
+ self.ci_loop = ci_loop
+ self.tags = tags
+ self.url = url
+ self.blocking = blocking
+ self.domains = domains
+ self.dependencies = dependencies
+ self.version = version
+ self.criteria = criteria
+ self.tier = tier
+ self.trust = trust
+ self.catalog_description = catalog_description
+ self.description = description
diff --git a/testapi/testapi-client/testapiclient/tests/unit/test_app.py b/testapi/testapi-client/testapiclient/tests/unit/test_app.py
new file mode 100644
index 0000000..c20b27f
--- /dev/null
+++ b/testapi/testapi-client/testapiclient/tests/unit/test_app.py
@@ -0,0 +1,50 @@
+import urllib
+
+from mock import mock
+
+from testapiclient import main
+from testapiclient.tests.unit import utils
+from testapiclient.tests.unit import fakes
+
+
+class MainTest(utils.TestCommand):
+ def setUp(self):
+ super(MainTest, self).setUp()
+ self.app = main.TestAPIClient()
+ self.cas_sever = '{}{}{}'.format(
+ self.env_variables['testapi_cas_auth_url'],
+ urllib.quote(self.env_variables['testapi_url']),
+ self.env_variables['testapi_cas_signin_return'])
+ self.headers = {
+ 'Content-type': 'application/json',
+ 'Accept': 'text/plain'}
+
+ def test_auth_success(self):
+ self.post_mock.return_value = fakes.FakeResponse(
+ data={'text': "success"})
+ self.app.run(
+ ['-u', 'user', '-p', 'pass', 'pod', 'create',
+ '{"name": "asfad"}'])
+ self.post_mock.assert_called_with(
+ 'http://localhost:8000/api/v1/pods',
+ data='{"name": "asfad"}',
+ headers=self.headers)
+
+ def test_auth_failure(self):
+ self.post_mock.return_value = fakes.FakeResponse(
+ data={'text': "login"})
+ self.app.run(
+ ['-u', 'user', '-p', 'pass', 'pod', 'create',
+ '{"name": "asfad"}'])
+ self.post_mock.assert_called_once_with(
+ self.cas_sever,
+ {'pass': 'pass', 'name': 'user', 'form_id': 'user_login'}
+ )
+
+ def test_auth_not_called(self):
+ self.auth_post = mock.patch(
+ 'testapiclient.utils.clientmanager.ClientManager.auth').start()
+ self.app.run(['pod', 'get'])
+ self.auth_post.assert_not_called()
+ self.get_mock.assert_called_once_with(
+ 'http://localhost:8000/api/v1/pods', headers=self.headers)
diff --git a/testapi/testapi-client/testapiclient/tests/unit/test_deployresults.py b/testapi/testapi-client/testapiclient/tests/unit/test_deployresults.py
new file mode 100644
index 0000000..0e0385b
--- /dev/null
+++ b/testapi/testapi-client/testapiclient/tests/unit/test_deployresults.py
@@ -0,0 +1,109 @@
+import json
+
+from mock import mock
+from six.moves.urllib import parse
+import testtools
+
+from testapiclient.cli import deployresults
+from testapiclient.tests.unit import fakes
+from testapiclient.tests.unit import utils
+from testapiclient.utils import clientmanager
+
+
+class DeployresultTest(utils.TestCommand):
+ def setUp(self):
+ super(DeployresultTest, self).setUp()
+ self.base_url = parse.urljoin(self.api_url, 'deployresults')
+ self.deployresult_json = {
+ 'job_name': 'daisy-deploy',
+ 'scenario': 'test-scenario',
+ 'stop_date': '2018-04-09 13:44:53',
+ 'upstream_job_name': 'test-job',
+ 'build_id': 'test-build',
+ 'version': 'test-version',
+ 'pod_name': 'test-pod',
+ 'criteria': 'test-criteria',
+ 'installer': 'test-installer',
+ 'start_date': '2018-04-09 13:44:53',
+ 'details': 'test-details',
+ 'upstream_build_id': 'test-stream'
+ }
+ self.deployresult_string = json.dumps(self.deployresult_json)
+
+
+class DeployresultGetTest(DeployresultTest):
+
+ def setUp(self):
+ super(DeployresultGetTest, self).setUp()
+ self.deployresults_rsp = {'deployresults': [self.deployresult_json]}
+
+ def test_get(self):
+ self.get_mock.return_value = fakes.FakeResponse(
+ data=self.deployresults_rsp)
+ deployresult_get = deployresults.DeployresultGet(
+ self.app, mock.Mock())
+ args = ['-job-name', 'dfs']
+ verifies = [('job_name', 'dfs')]
+ parsed_args = self.check_parser(deployresult_get, args, verifies)
+ deployresult_get.take_action(parsed_args)
+ self.get_mock.assert_called_once_with(
+ self.base_url + '?job_name=dfs',
+ headers=clientmanager.ClientManager.headers)
+
+ def test_get_all(self):
+ self.get_mock.return_value = fakes.FakeResponse(
+ data=self.deployresults_rsp)
+ deployresult_get = deployresults.DeployresultGet(
+ self.app, mock.Mock())
+ args = []
+ verifies = []
+ parsed_args = self.check_parser(deployresult_get, args, verifies)
+ deployresult_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 = fakes.FakeResponse(
+ data=self.deployresult_json)
+ deployresult_get_one = deployresults.DeployresultGetOne(
+ self.app, mock.Mock())
+ args = ['def']
+ verifies = [('deployresult_id', 'def')]
+ parsed_args = self.check_parser(
+ deployresult_get_one, args, verifies)
+ deployresult_get_one.take_action(parsed_args)
+ self.get_mock.assert_called_once_with(
+ self.base_url + '/def',
+ headers=clientmanager.ClientManager.headers)
+
+
+class DeployresultCreateTest(DeployresultTest):
+
+ def setUp(self):
+ super(DeployresultCreateTest, self).setUp()
+
+ def test_create_success(self):
+ succ_rsp = {
+ 'href': '{}/{}'.format(self.base_url,
+ self.deployresult_json.get('project_name'))
+ }
+ self.post_mock.return_value = fakes.FakeResponse(data=succ_rsp)
+ deployresult_create = deployresults.DeployresultCreate(
+ self.app, mock.Mock())
+ args = [self.deployresult_string]
+ verifies = [('deployresult', self.deployresult_json)]
+ parsed_args = self.check_parser(deployresult_create, args, verifies)
+ deployresult_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
+ deployresult_create = deployresults.DeployresultCreate(
+ self.app, mock.Mock())
+ args = [self.deployresult_string]
+ verifies = [('deployresult', self.deployresult_json)]
+ parsed_args = self.check_parser(
+ deployresult_create, args, verifies)
+ deployresult_create.take_action(parsed_args)
diff --git a/testapi/testapi-client/testapiclient/tests/unit/test_deployresults_client.py b/testapi/testapi-client/testapiclient/tests/unit/test_deployresults_client.py
new file mode 100644
index 0000000..03288fe
--- /dev/null
+++ b/testapi/testapi-client/testapiclient/tests/unit/test_deployresults_client.py
@@ -0,0 +1,81 @@
+import json
+
+from six.moves.urllib import parse
+import testtools
+
+from testapiclient.client import deploy_results
+from testapiclient.tests.unit import fakes
+from testapiclient.tests.unit import utils
+from testapiclient.utils import clientmanager
+
+
+class DeployResultsClientTest(utils.TestCommand):
+ def setUp(self):
+ super(DeployResultsClientTest, self).setUp()
+ self.base_url = parse.urljoin(self.api_url, 'deployresults')
+ self.deployresult_json = {
+ 'project_name': 'functest',
+ 'scenario': 'test-scenario',
+ 'stop_date': '2018-04-09 13:44:53',
+ 'case_name': 'test-case',
+ 'build_tag': 'test-build',
+ 'version': 'test-version',
+ 'pod_name': 'test-pod',
+ 'criteria': 'test-criteria',
+ 'installer': 'test-installer',
+ 'start_date': '2018-04-09 13:44:53',
+ 'details': 'test-details'
+ }
+ self.deployresult_id = '5a6dc1089a07c80f3c9f8d62'
+ self.deployresult_string = json.dumps(self.deployresult_json)
+ self.deployresult_client = deploy_results.DeployResultsClient()
+
+
+class DeployResultsClientGetTest(DeployResultsClientTest):
+
+ def setUp(self):
+ super(DeployResultsClientGetTest, self).setUp()
+ self.deployresults_rsp = {'deployresults': [self.deployresult_json]}
+
+ def test_get(self):
+ self.get_mock.return_value = fakes.FakeResponse(
+ data=self.deployresults_rsp)
+ self.deployresult_client.get()
+ self.get_mock.assert_called_once_with(
+ self.base_url,
+ headers=clientmanager.ClientManager.headers)
+
+ def test_get_search(self):
+ self.get_mock.return_value = fakes.FakeResponse(
+ data=self.deployresults_rsp)
+ self.deployresult_client.get(name='deployresult1')
+ self.get_mock.assert_called_once_with(
+ self.base_url + '?name=deployresult1',
+ headers=clientmanager.ClientManager.headers)
+
+ def test_get_one(self):
+ self.get_mock.return_value = fakes.FakeResponse(
+ data=self.deployresult_json)
+ self.deployresult_client.get_one('2333')
+ self.get_mock.assert_called_once_with(
+ self.base_url + '/2333',
+ headers=clientmanager.ClientManager.headers)
+
+
+class DeployResultsClientCreateTest(DeployResultsClientTest):
+
+ def setUp(self):
+ super(DeployResultsClientCreateTest, self).setUp()
+ self.succ_rsp = {
+ 'href': '{}/{}'.format(self.base_url, self.deployresult_id)
+ }
+
+ def test_create_success(self):
+ self.post_mock.return_value = fakes.FakeResponse(data=self.succ_rsp)
+ self.deployresult_client.create(self.deployresult_json)
+ 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
+ self.deployresult_client.create(self.deployresult_json)
diff --git a/testapi/testapi-client/testapiclient/tests/unit/test_placeholder.py b/testapi/testapi-client/testapiclient/tests/unit/test_placeholder.py
deleted file mode 100644
index 2b7ad46..0000000
--- a/testapi/testapi-client/testapiclient/tests/unit/test_placeholder.py
+++ /dev/null
@@ -1,6 +0,0 @@
-import testtools
-
-
-class TestPlaceHolder(testtools.TestCase):
- def test_placeholder(self):
- self.assertEqual(1, 1)
diff --git a/testapi/testapi-client/testapiclient/tests/unit/test_pod_client.py b/testapi/testapi-client/testapiclient/tests/unit/test_pod_client.py
new file mode 100644
index 0000000..1df5660
--- /dev/null
+++ b/testapi/testapi-client/testapiclient/tests/unit/test_pod_client.py
@@ -0,0 +1,89 @@
+import json
+
+from six.moves.urllib import parse
+import testtools
+
+from testapiclient.client import pods
+from testapiclient.tests.unit import fakes
+from testapiclient.tests.unit import utils
+from testapiclient.utils import clientmanager
+
+
+class PodClientTest(utils.TestCommand):
+ def setUp(self):
+ super(PodClientTest, self).setUp()
+ self.base_url = parse.urljoin(self.api_url, 'pods')
+ self.pod_json = {
+ 'role': 'community-ci',
+ 'name': 'test_pod',
+ 'details': '',
+ 'mode': 'metal'
+ }
+ self.pod_client = pods.PodsClient()
+ self.pod_string = json.dumps(self.pod_json)
+
+
+class PodClientGetTest(PodClientTest):
+
+ def setUp(self):
+ super(PodClientGetTest, self).setUp()
+ self.pods_rsp = {'pods': [self.pod_json]}
+
+ def test_get(self):
+ self.get_mock.return_value = fakes.FakeResponse(data=self.pods_rsp)
+ self.pod_client.get()
+ self.get_mock.assert_called_once_with(
+ self.base_url,
+ headers=clientmanager.ClientManager.headers)
+
+ def test_get_search(self):
+ self.get_mock.return_value = fakes.FakeResponse(data=self.pods_rsp)
+ self.pod_client.get(name='pod1')
+ self.get_mock.assert_called_once_with(
+ self.base_url + '?name=pod1',
+ headers=clientmanager.ClientManager.headers)
+
+ def test_get_one(self):
+ self.get_mock.return_value = fakes.FakeResponse(data=self.pod_json)
+ self.pod_client.get_one('def')
+ self.get_mock.assert_called_once_with(
+ self.base_url + '/def',
+ headers=clientmanager.ClientManager.headers)
+
+
+class PodClientCreateTest(PodClientTest):
+
+ def setUp(self):
+ super(PodClientCreateTest, self).setUp()
+ self.succ_rsp = {
+ 'href': '{}/{}'.format(self.base_url, self.pod_json.get('name'))
+ }
+
+ def test_create_success(self):
+ self.post_mock.return_value = fakes.FakeResponse(data=self.succ_rsp)
+ self.pod_client.create(self.pod_json)
+ 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
+ self.pod_client.create(self.pod_json)
+
+
+class PodClientDeleteTest(PodClientTest):
+
+ def setUp(self):
+ super(PodClientDeleteTest, self).setUp()
+
+ def test_delete_success(self):
+ self.delete_mock.return_value = fakes.FakeResponse()
+ self.pod_client.delete('def')
+ 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
+ self.pod_client.delete('def')
diff --git a/testapi/testapi-client/testapiclient/tests/unit/test_project_client.py b/testapi/testapi-client/testapiclient/tests/unit/test_project_client.py
new file mode 100644
index 0000000..7aa11e6
--- /dev/null
+++ b/testapi/testapi-client/testapiclient/tests/unit/test_project_client.py
@@ -0,0 +1,111 @@
+import json
+
+from six.moves.urllib import parse
+import testtools
+
+from testapiclient.client import projects
+from testapiclient.tests.unit import fakes
+from testapiclient.tests.unit import utils
+from testapiclient.utils import clientmanager
+
+
+class ProjectClientTest(utils.TestCommand):
+ def setUp(self):
+ super(ProjectClientTest, self).setUp()
+ self.base_url = parse.urljoin(self.api_url, 'projects')
+ self.project_json = {
+ 'description': 'test_description',
+ 'name': 'test_project',
+ }
+ self.project_client = projects.ProjectsClient()
+ self.project_string = json.dumps(self.project_json)
+
+
+class ProjectClientGetTest(ProjectClientTest):
+
+ def setUp(self):
+ super(ProjectClientGetTest, self).setUp()
+ self.projects_rsp = {'projects': [self.project_json]}
+
+ def test_get(self):
+ self.get_mock.return_value = fakes.FakeResponse(
+ data=self.projects_rsp)
+ self.project_client.get()
+ self.get_mock.assert_called_once_with(
+ self.base_url,
+ headers=clientmanager.ClientManager.headers)
+
+ def test_get_search(self):
+ self.get_mock.return_value = fakes.FakeResponse(
+ data=self.projects_rsp)
+ self.project_client.get(name='project1')
+ self.get_mock.assert_called_once_with(
+ self.base_url + '?name=project1',
+ headers=clientmanager.ClientManager.headers)
+
+ def test_get_one(self):
+ self.get_mock.return_value = fakes.FakeResponse(
+ data=self.project_json)
+ self.project_client.get_one('def')
+ self.get_mock.assert_called_once_with(
+ self.base_url + '/def',
+ headers=clientmanager.ClientManager.headers)
+
+
+class ProjectClientCreateTest(ProjectClientTest):
+
+ def setUp(self):
+ super(ProjectClientCreateTest, self).setUp()
+ self.succ_rsp = {
+ 'href': '{}/{}'.format(
+ self.base_url, self.project_json.get('name'))
+ }
+
+ def test_create_success(self):
+ self.post_mock.return_value = fakes.FakeResponse(
+ data=self.succ_rsp)
+ self.project_client.create(self.project_json)
+ 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
+ self.project_client.create(self.project_json)
+
+
+class ProjectClientDeleteTest(ProjectClientTest):
+
+ def setUp(self):
+ super(ProjectClientDeleteTest, self).setUp()
+
+ def test_delete_success(self):
+ self.delete_mock.return_value = fakes.FakeResponse()
+ self.project_client.delete('def')
+ 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
+ self.project_client.delete('def')
+
+
+class ProjectClientUpdateTest(ProjectClientTest):
+
+ def setUp(self):
+ super(ProjectClientUpdateTest, self).setUp()
+
+ def test_update_success(self):
+ self.put_mock.return_value = fakes.FakeResponse()
+ self.project_client.update('def', self.project_json)
+ self.put_mock.assert_called_once_with(
+ self.base_url + '/def',
+ data=self.project_string,
+ headers=clientmanager.ClientManager.headers)
+
+ def test_update_failure(self):
+ with testtools.ExpectedException(Exception, 'Update failed: Error'):
+ self.put_mock.return_value = utils.FAKE_FAILURE
+ self.project_client.update('def', self.project_json)
diff --git a/testapi/testapi-client/testapiclient/tests/unit/test_results.py b/testapi/testapi-client/testapiclient/tests/unit/test_results.py
new file mode 100644
index 0000000..83bcc9f
--- /dev/null
+++ b/testapi/testapi-client/testapiclient/tests/unit/test_results.py
@@ -0,0 +1,98 @@
+import json
+
+from mock import mock
+from six.moves.urllib import parse
+import testtools
+
+from testapiclient.cli import results
+from testapiclient.tests.unit import fakes
+from testapiclient.tests.unit import utils
+from testapiclient.utils import clientmanager
+
+
+class ResultTest(utils.TestCommand):
+ def setUp(self):
+ super(ResultTest, self).setUp()
+ self.base_url = parse.urljoin(self.api_url, 'results')
+ self.result_json = {
+ 'project_name': 'functest',
+ 'scenario': 'test-scenario',
+ 'stop_date': '2018-04-09 13:44:53',
+ 'case_name': 'test-case',
+ 'build_tag': 'test-build',
+ 'version': 'test-version',
+ 'pod_name': 'test-pod',
+ 'criteria': 'test-criteria',
+ 'installer': 'test-installer',
+ 'start_date': '2018-04-09 13:44:53',
+ 'details': 'test-details'
+ }
+ self.result_string = json.dumps(self.result_json)
+
+
+class ResultGetTest(ResultTest):
+
+ def setUp(self):
+ super(ResultGetTest, self).setUp()
+ self.results_rsp = {'results': [self.result_json]}
+
+ def test_get(self):
+ self.get_mock.return_value = fakes.FakeResponse(data=self.results_rsp)
+ result_get = results.ResultGet(self.app, mock.Mock())
+ args = ['-case', 'dfs']
+ verifies = [('case', 'dfs')]
+ parsed_args = self.check_parser(result_get, args, verifies)
+ result_get.take_action(parsed_args)
+ self.get_mock.assert_called_once_with(
+ self.base_url + '?case=dfs',
+ headers=clientmanager.ClientManager.headers)
+
+ def test_get_all(self):
+ self.get_mock.return_value = fakes.FakeResponse(data=self.results_rsp)
+ result_get = results.ResultGet(self.app, mock.Mock())
+ args = []
+ verifies = []
+ parsed_args = self.check_parser(result_get, args, verifies)
+ result_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 = fakes.FakeResponse(data=self.result_json)
+ result_get_one = results.ResultGetOne(self.app, mock.Mock())
+ args = ['def']
+ verifies = [('result_id', 'def')]
+ parsed_args = self.check_parser(result_get_one, args, verifies)
+ result_get_one.take_action(parsed_args)
+ self.get_mock.assert_called_once_with(
+ self.base_url + '/def',
+ headers=clientmanager.ClientManager.headers)
+
+
+class ResultCreateTest(ResultTest):
+
+ def setUp(self):
+ super(ResultCreateTest, self).setUp()
+
+ def test_create_success(self):
+ succ_rsp = {
+ 'href': '{}/{}'.format(self.base_url,
+ self.result_json.get('project_name'))
+ }
+ self.post_mock.return_value = fakes.FakeResponse(data=succ_rsp)
+ result_create = results.ResultCreate(self.app, mock.Mock())
+ args = [self.result_string]
+ verifies = [('result', self.result_json)]
+ parsed_args = self.check_parser(result_create, args, verifies)
+ result_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
+ result_create = results.ResultCreate(self.app, mock.Mock())
+ args = [self.result_string]
+ verifies = [('result', self.result_json)]
+ parsed_args = self.check_parser(result_create, args, verifies)
+ result_create.take_action(parsed_args)
diff --git a/testapi/testapi-client/testapiclient/tests/unit/test_results_client.py b/testapi/testapi-client/testapiclient/tests/unit/test_results_client.py
new file mode 100644
index 0000000..ae677f7
--- /dev/null
+++ b/testapi/testapi-client/testapiclient/tests/unit/test_results_client.py
@@ -0,0 +1,78 @@
+import json
+
+from six.moves.urllib import parse
+import testtools
+
+from testapiclient.client import results
+from testapiclient.tests.unit import fakes
+from testapiclient.tests.unit import utils
+from testapiclient.utils import clientmanager
+
+
+class ResultClientTest(utils.TestCommand):
+ def setUp(self):
+ super(ResultClientTest, self).setUp()
+ self.base_url = parse.urljoin(self.api_url, 'results')
+ self.result_json = {
+ 'project_name': 'functest',
+ 'scenario': 'test-scenario',
+ 'stop_date': '2018-04-09 13:44:53',
+ 'case_name': 'test-case',
+ 'build_tag': 'test-build',
+ 'version': 'test-version',
+ 'pod_name': 'test-pod',
+ 'criteria': 'test-criteria',
+ 'installer': 'test-installer',
+ 'start_date': '2018-04-09 13:44:53',
+ 'details': 'test-details'
+ }
+ self.result_id = '5a6dc1089a07c80f3c9f8d62'
+ self.result_string = json.dumps(self.result_json)
+ self.result_client = results.ResultsClient()
+
+
+class ResultClientGetTest(ResultClientTest):
+
+ def setUp(self):
+ super(ResultClientGetTest, self).setUp()
+ self.results_rsp = {'results': [self.result_json]}
+
+ def test_get(self):
+ self.get_mock.return_value = fakes.FakeResponse(data=self.results_rsp)
+ self.result_client.get()
+ self.get_mock.assert_called_once_with(
+ self.base_url,
+ headers=clientmanager.ClientManager.headers)
+
+ def test_get_search(self):
+ self.get_mock.return_value = fakes.FakeResponse(data=self.results_rsp)
+ self.result_client.get(name='result1')
+ self.get_mock.assert_called_once_with(
+ self.base_url + '?name=result1',
+ headers=clientmanager.ClientManager.headers)
+
+ def test_get_one(self):
+ self.get_mock.return_value = fakes.FakeResponse(data=self.result_json)
+ self.result_client.get_one('2333')
+ self.get_mock.assert_called_once_with(
+ self.base_url + '/2333',
+ headers=clientmanager.ClientManager.headers)
+
+
+class ResultClientCreateTest(ResultClientTest):
+
+ def setUp(self):
+ super(ResultClientCreateTest, self).setUp()
+ self.succ_rsp = {
+ 'href': '{}/{}'.format(self.base_url, self.result_id)
+ }
+
+ def test_create_success(self):
+ self.post_mock.return_value = fakes.FakeResponse(data=self.succ_rsp)
+ self.result_client.create(self.result_json)
+ 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
+ self.result_client.create(self.result_json)
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..b14cf04
--- /dev/null
+++ b/testapi/testapi-client/testapiclient/tests/unit/test_scenario.py
@@ -0,0 +1,147 @@
+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 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_scenario_client.py b/testapi/testapi-client/testapiclient/tests/unit/test_scenario_client.py
new file mode 100644
index 0000000..6e9e0fa
--- /dev/null
+++ b/testapi/testapi-client/testapiclient/tests/unit/test_scenario_client.py
@@ -0,0 +1,104 @@
+import json
+
+from six.moves.urllib import parse
+import testtools
+
+from testapiclient.client import scenarios
+from testapiclient.tests.unit import fakes
+from testapiclient.tests.unit import utils
+from testapiclient.utils import clientmanager
+
+
+class ScenarioClientTest(utils.TestCommand):
+ def setUp(self):
+ super(ScenarioClientTest, self).setUp()
+ self.base_url = parse.urljoin(self.api_url, 'scenarios')
+ self.scenario_json = {
+ "installers": [],
+ "name": "test_scenario"
+ }
+ self.scenario_client = scenarios.ScenariosClient()
+ self.scenario_string = json.dumps(self.scenario_json)
+
+
+class ScenarioClientGetTest(ScenarioClientTest):
+
+ def setUp(self):
+ super(ScenarioClientGetTest, self).setUp()
+ self.scenarios_rsp = {'scenarios': [self.scenario_json]}
+
+ def test_get(self):
+ self.get_mock.return_value = fakes.FakeResponse(
+ data=self.scenarios_rsp)
+ self.scenario_client.get()
+ self.get_mock.assert_called_once_with(
+ self.base_url,
+ headers=clientmanager.ClientManager.headers)
+
+ def test_get_one(self):
+ self.get_mock.return_value = fakes.FakeResponse(
+ data=self.scenario_json)
+ self.scenario_client.get_one('def')
+ self.get_mock.assert_called_once_with(
+ self.base_url + '/def',
+ headers=clientmanager.ClientManager.headers)
+
+
+class ScenarioClientCreateTest(ScenarioClientTest):
+
+ def setUp(self):
+ super(ScenarioClientCreateTest, self).setUp()
+ self.succ_rsp = {
+ 'href': '{}/{}'.format(
+ self.base_url, self.scenario_json.get('name'))
+ }
+
+ def test_create_success(self):
+ self.post_mock.return_value = fakes.FakeResponse(
+ data=self.succ_rsp)
+ self.scenario_client.create(self.scenario_json)
+ 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
+ self.scenario_client.create(self.scenario_json)
+
+
+class ScenarioClientDeleteTest(ScenarioClientTest):
+
+ def setUp(self):
+ super(ScenarioClientDeleteTest, self).setUp()
+
+ def test_delete_success(self):
+ self.delete_mock.return_value = fakes.FakeResponse()
+ self.scenario_client.delete('def')
+ 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
+ self.scenario_client.delete('def')
+
+
+class ScenarioClientUpdateTest(ScenarioClientTest):
+
+ def setUp(self):
+ super(ScenarioClientUpdateTest, self).setUp()
+
+ def test_update_success(self):
+ self.put_mock.return_value = fakes.FakeResponse()
+ self.scenario_client.update(
+ 'def', self.scenario_json)
+ self.put_mock.assert_called_once_with(
+ self.base_url + '/def',
+ data=self.scenario_string,
+ headers=clientmanager.ClientManager.headers)
+
+ def test_update_failure(self):
+ with testtools.ExpectedException(Exception, 'Update failed: Error'):
+ self.put_mock.return_value = utils.FAKE_FAILURE
+ self.scenario_client.update('def', self.scenario_json)
diff --git a/testapi/testapi-client/testapiclient/tests/unit/test_scenario_custom.py b/testapi/testapi-client/testapiclient/tests/unit/test_scenario_custom.py
new file mode 100644
index 0000000..e3f89c0
--- /dev/null
+++ b/testapi/testapi-client/testapiclient/tests/unit/test_scenario_custom.py
@@ -0,0 +1,88 @@
+
+
+from mock import mock
+from six.moves.urllib import parse
+
+from testapiclient.cli import scenarios
+from testapiclient.tests.unit import fakes
+from testapiclient.tests.unit import utils
+
+
+class CustomTest(utils.TestCommand):
+ def setUp(self):
+ super(CustomTest, self).setUp()
+ self.base_url = parse.urljoin(self.api_url, 'scenarios/{}/customs')
+ self.scenario_name = 's1'
+ self.custom_input = 'custom'
+ self.custom_parsed = ['custom']
+
+
+class CustomCreateTest(CustomTest):
+
+ def setUp(self):
+ super(CustomCreateTest, self).setUp()
+
+ def test_create_success(self):
+ self.post_mock.return_value = fakes.FakeResponse(data=None)
+ custom_create = scenarios.CustomCreate(self.app, mock.Mock())
+ args = [
+ '--scenario-name', 's1', '--installer', 'i1', '--version',
+ 'v1', '--project', 'p1', self.custom_input]
+ verifies = [
+ ('scenario_name', 's1'),
+ ('installer', 'i1'),
+ ('version', 'v1'),
+ ('project', 'p1'),
+ ('custom', self.custom_parsed)]
+ parsed_args = self.check_parser(custom_create, args, verifies)
+ custom_create.take_action(parsed_args)
+ self.post_mock.assert_called_once()
+
+
+class CustomDeleteTest(CustomTest):
+
+ def setUp(self):
+ super(CustomDeleteTest, self).setUp()
+
+ def test_delete_success(self):
+ self.delete_mock.return_value = fakes.FakeResponse(data=None)
+ custom_delete = scenarios.CustomDelete(self.app, mock.Mock())
+ args = [
+ '--scenario-name', 's1', '--installer', 'i1',
+ '--version', 'v1', '--project', 'p1', 'def']
+ verifies = [
+ ('scenario_name', 's1'),
+ ('installer', 'i1'),
+ ('version', 'v1'),
+ ('project', 'p1'),
+ ('name', ['def'])]
+ parsed_args = self.check_parser(custom_delete, args, verifies)
+ custom_delete.take_action(parsed_args)
+ kall = self.delete_mock.call_args
+ args, kwargs = kall
+ self.assert_url(
+ args[0],
+ self.base_url + '?version=v1&project=p1&installer=i1')
+
+
+class CustomPutTest(CustomTest):
+
+ def setUp(self):
+ super(CustomPutTest, self).setUp()
+
+ def test_put_success(self):
+ self.put_mock.return_value = fakes.FakeResponse(
+ data=None)
+ custom_put = scenarios.CustomPut(self.app, mock.Mock())
+ args = [
+ '--scenario-name', 's1', '--installer', 'i1', '--version', 'v1',
+ '--project', 'p1', self.custom_input]
+ verifies = [
+ ('scenario_name', 's1'),
+ ('installer', 'i1'),
+ ('version', 'v1'),
+ ('project', 'p1'),
+ ('custom', self.custom_parsed)]
+ parsed_args = self.check_parser(custom_put, args, verifies)
+ custom_put.take_action(parsed_args)
+ self.put_mock.assert_called_once()
diff --git a/testapi/testapi-client/testapiclient/tests/unit/test_scenario_custom_client.py b/testapi/testapi-client/testapiclient/tests/unit/test_scenario_custom_client.py
new file mode 100644
index 0000000..7c6d62c
--- /dev/null
+++ b/testapi/testapi-client/testapiclient/tests/unit/test_scenario_custom_client.py
@@ -0,0 +1,106 @@
+from six.moves.urllib import parse
+import testtools
+
+from testapiclient.client import scenarios
+from testapiclient.tests.unit import fakes
+from testapiclient.tests.unit import utils
+
+
+class CustomClientTest(utils.TestCommand):
+ def setUp(self):
+ super(CustomClientTest, self).setUp()
+ self.scenario_name = 'scenrio1'
+ self.base_url = parse.urljoin(
+ self.api_url,
+ 'scenarios/{}/customs'.format(self.scenario_name))
+ self.custom_raw = 'custom'
+ self.custom_input = ['custom']
+ self.installer_name = 'installer'
+ self.version_name = 'version'
+ self.project_name = 'project'
+ self.custom_client = scenarios.CustomsClient()
+
+
+class CustomClientCreateTest(CustomClientTest):
+
+ def setUp(self):
+ super(CustomClientCreateTest, self).setUp()
+ self.succ_rsp = {
+ 'href': '{}/{}'.format(
+ self.base_url, self.scenario_name)
+ }
+
+ def test_create_success(self):
+ self.post_mock.return_value = fakes.FakeResponse(
+ data=self.succ_rsp)
+ self.custom_client.create(
+ self.scenario_name, self.installer_name,
+ self.version_name, self.project_name,
+ self.custom_raw)
+ 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
+ self.custom_client.create(
+ self.scenario_name, self.installer_name,
+ self.version_name, self.project_name,
+ self.custom_raw)
+
+
+class CustomClientDeleteTest(CustomClientTest):
+
+ def setUp(self):
+ super(CustomClientDeleteTest, self).setUp()
+
+ def test_delete_success(self):
+ self.delete_mock.return_value = fakes.FakeResponse()
+ self.custom_client.delete(
+ self.scenario_name, self.installer_name,
+ self.version_name, self.project_name,
+ self.custom_raw)
+ kall = self.delete_mock.call_args
+ args, kwargs = kall
+ self.assert_url(
+ args[0],
+ self.base_url +
+ '?installer=installer&version=version&project=project')
+
+ def test_delete_failure(self):
+ with testtools.ExpectedException(Exception, 'Delete failed: Error'):
+ self.delete_mock.return_value = utils.FAKE_FAILURE
+ self.custom_client.delete(
+ self.scenario_name, self.installer_name,
+ self.version_name, self.project_name,
+ self.custom_raw)
+
+
+class CustomClientUpdateTest(CustomClientTest):
+
+ def setUp(self):
+ super(CustomClientUpdateTest, self).setUp()
+
+ def test_update_success(self):
+ self.put_mock.return_value = fakes.FakeResponse()
+ self.custom_client.update(
+ self.scenario_name,
+ self.installer_name,
+ self.version_name,
+ self.project_name,
+ self.custom_raw)
+ kall = self.put_mock.call_args
+ args, kwargs = kall
+ self.assert_url(
+ args[0],
+ self.base_url +
+ '?installer=installer&version=version&project=project')
+
+ def test_update_failure(self):
+ with testtools.ExpectedException(Exception, 'Update failed: Error'):
+ self.put_mock.return_value = utils.FAKE_FAILURE
+ self.custom_client.update(
+ self.scenario_name,
+ self.installer_name,
+ self.version_name,
+ self.project_name,
+ self.custom_raw)
diff --git a/testapi/testapi-client/testapiclient/tests/unit/test_scenario_installer.py b/testapi/testapi-client/testapiclient/tests/unit/test_scenario_installer.py
new file mode 100644
index 0000000..2246a59
--- /dev/null
+++ b/testapi/testapi-client/testapiclient/tests/unit/test_scenario_installer.py
@@ -0,0 +1,74 @@
+import json
+
+from mock import mock
+from six.moves.urllib import parse
+
+from testapiclient.cli import scenarios
+from testapiclient.tests.unit import fakes
+from testapiclient.tests.unit import utils
+from testapiclient.utils import clientmanager
+
+
+class InstallerTest(utils.TestCommand):
+ def setUp(self):
+ super(InstallerTest, self).setUp()
+ self.base_url = parse.urljoin(self.api_url, 'scenarios/{}/installers')
+ self.scenario_name = 's1'
+ self.installer_json = {
+ 'versions': [],
+ 'installer': 'test-installer',
+ }
+ self.installer_string = json.dumps(self.installer_json)
+
+
+class InstallerCreateTest(InstallerTest):
+
+ def setUp(self):
+ super(InstallerCreateTest, self).setUp()
+
+ def test_create_success(self):
+ self.post_mock.return_value = fakes.FakeResponse(data=None)
+ installer_create = scenarios.InstallerCreate(self.app, mock.Mock())
+ args = ['--scenario-name', 's1', self.installer_string]
+ verifies = [
+ ('scenario_name', 's1'),
+ ('installer', self.installer_json)]
+ parsed_args = self.check_parser(installer_create, args, verifies)
+ installer_create.take_action(parsed_args)
+ self.post_mock.assert_called_once()
+
+
+class InstallerDeleteTest(InstallerTest):
+
+ def setUp(self):
+ super(InstallerDeleteTest, self).setUp()
+
+ def test_delete_success(self):
+ self.delete_mock.return_value = fakes.FakeResponse(data=None)
+ installer_delete = scenarios.InstallerDelete(self.app, mock.Mock())
+ args = ['--scenario-name', 's1', 'def']
+ verifies = [('scenario_name', 's1'), ('name', ['def'])]
+ parsed_args = self.check_parser(installer_delete, args, verifies)
+ installer_delete.take_action(parsed_args)
+ self.delete_mock.assert_called_once_with(
+ self.base_url.format(parsed_args.scenario_name),
+ data=json.dumps(['def']),
+ headers=clientmanager.ClientManager.headers)
+
+
+class InstallerPutTest(InstallerTest):
+
+ def setUp(self):
+ super(InstallerPutTest, self).setUp()
+
+ def test_put_success(self):
+ self.put_mock.return_value = fakes.FakeResponse(
+ data=None)
+ installer_put = scenarios.InstallerPut(self.app, mock.Mock())
+ args = ['--scenario-name', 's1', self.installer_string]
+ verifies = [
+ ('scenario_name', 's1'),
+ ('installer', self.installer_json)]
+ parsed_args = self.check_parser(installer_put, args, verifies)
+ installer_put.take_action(parsed_args)
+ self.put_mock.assert_called_once()
diff --git a/testapi/testapi-client/testapiclient/tests/unit/test_scenario_installer_client.py b/testapi/testapi-client/testapiclient/tests/unit/test_scenario_installer_client.py
new file mode 100644
index 0000000..71ba150
--- /dev/null
+++ b/testapi/testapi-client/testapiclient/tests/unit/test_scenario_installer_client.py
@@ -0,0 +1,86 @@
+import json
+
+from six.moves.urllib import parse
+import testtools
+
+from testapiclient.client import scenarios
+from testapiclient.tests.unit import fakes
+from testapiclient.tests.unit import utils
+from testapiclient.utils import clientmanager
+
+
+class InstallerClientTest(utils.TestCommand):
+ def setUp(self):
+ super(InstallerClientTest, self).setUp()
+ self.scenario_name = 'scenrio1'
+ self.base_url = parse.urljoin(
+ self.api_url,
+ 'scenarios/{}/installers'.format(self.scenario_name))
+ self.installer_json = {
+ 'versions': [],
+ 'installer': 'test-installer',
+ }
+ self.installer_client = scenarios.InstallersClient()
+ self.installer_string = json.dumps(self.installer_json)
+
+
+class InstallerClientCreateTest(InstallerClientTest):
+
+ def setUp(self):
+ super(InstallerClientCreateTest, self).setUp()
+ self.succ_rsp = {
+ 'href': '{}/{}'.format(
+ self.base_url, self.installer_json.get('name'))
+ }
+
+ def test_create_success(self):
+ self.post_mock.return_value = fakes.FakeResponse(
+ data=self.succ_rsp)
+ self.installer_client.create(self.scenario_name, self.installer_json)
+ 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
+ self.installer_client.create(
+ self.scenario_name, self.installer_json)
+
+
+class InstallerClientDeleteTest(InstallerClientTest):
+
+ def setUp(self):
+ super(InstallerClientDeleteTest, self).setUp()
+
+ def test_delete_success(self):
+ self.delete_mock.return_value = fakes.FakeResponse()
+ self.installer_client.delete(self.scenario_name, 'def')
+ self.delete_mock.assert_called_once_with(
+ self.base_url,
+ data=json.dumps(['def']),
+ headers=clientmanager.ClientManager.headers)
+
+ def test_delete_failure(self):
+ with testtools.ExpectedException(Exception, 'Delete failed: Error'):
+ self.delete_mock.return_value = utils.FAKE_FAILURE
+ self.installer_client.delete(self.scenario_name, 'def')
+
+
+class InstallerClientUpdateTest(InstallerClientTest):
+
+ def setUp(self):
+ super(InstallerClientUpdateTest, self).setUp()
+
+ def test_update_success(self):
+ self.put_mock.return_value = fakes.FakeResponse()
+ self.installer_client.update(
+ self.scenario_name,
+ self.installer_json)
+ self.put_mock.assert_called_once_with(
+ self.base_url,
+ data=self.installer_string,
+ headers=clientmanager.ClientManager.headers)
+
+ def test_update_failure(self):
+ with testtools.ExpectedException(Exception, 'Update failed: Error'):
+ self.put_mock.return_value = utils.FAKE_FAILURE
+ self.installer_client.update('def', self.installer_json)
diff --git a/testapi/testapi-client/testapiclient/tests/unit/test_scenario_project.py b/testapi/testapi-client/testapiclient/tests/unit/test_scenario_project.py
new file mode 100644
index 0000000..7bd6645
--- /dev/null
+++ b/testapi/testapi-client/testapiclient/tests/unit/test_scenario_project.py
@@ -0,0 +1,90 @@
+import json
+
+from mock import mock
+from six.moves.urllib import parse
+
+from testapiclient.cli import scenarios
+from testapiclient.tests.unit import fakes
+from testapiclient.tests.unit import utils
+
+
+class ProjectTest(utils.TestCommand):
+ def setUp(self):
+ super(ProjectTest, self).setUp()
+ self.base_url = parse.urljoin(self.api_url, 'scenarios/{}/projects')
+ self.scenario_name = 's1'
+ self.project_json = {
+ 'trust_indicators': [],
+ 'project': 'test-project',
+ 'scores': [],
+ 'customs': []
+ }
+ self.project_string = json.dumps(self.project_json)
+
+
+class ProjectCreateTest(ProjectTest):
+
+ def setUp(self):
+ super(ProjectCreateTest, self).setUp()
+
+ def test_create_success(self):
+ self.post_mock.return_value = fakes.FakeResponse(data=None)
+ project_create = scenarios.ProjectCreate(self.app, mock.Mock())
+ args = [
+ '--scenario-name', 's1', '--installer', 'i1', '--version', 'v1',
+ self.project_string]
+ verifies = [
+ ('scenario_name', 's1'),
+ ('installer', 'i1'),
+ ('version', 'v1'),
+ ('project', self.project_json)]
+ parsed_args = self.check_parser(project_create, args, verifies)
+ project_create.take_action(parsed_args)
+ self.post_mock.assert_called_once()
+
+
+class ProjectDeleteTest(ProjectTest):
+
+ def setUp(self):
+ super(ProjectDeleteTest, self).setUp()
+
+ def test_delete_success(self):
+ self.delete_mock.return_value = fakes.FakeResponse(data=None)
+ project_delete = scenarios.ProjectDelete(self.app, mock.Mock())
+ args = [
+ '--scenario-name', 's1', '--installer', 'i1', '--version', 'v1',
+ 'def']
+ verifies = [
+ ('scenario_name', 's1'),
+ ('installer', 'i1'),
+ ('version', 'v1'),
+ ('name', ['def'])]
+ parsed_args = self.check_parser(project_delete, args, verifies)
+ project_delete.take_action(parsed_args)
+ kall = self.delete_mock.call_args
+ args, kwargs = kall
+ self.assert_url(
+ args[0],
+ self.base_url + '?version=v1&installer=i1')
+
+
+class ProjectPutTest(ProjectTest):
+
+ def setUp(self):
+ super(ProjectPutTest, self).setUp()
+
+ def test_put_success(self):
+ self.put_mock.return_value = fakes.FakeResponse(
+ data=None)
+ project_put = scenarios.ProjectPut(self.app, mock.Mock())
+ args = [
+ '--scenario-name', 's1', '--installer', 'i1', '--version', 'v1',
+ self.project_string]
+ verifies = [
+ ('scenario_name', 's1'),
+ ('installer', 'i1'),
+ ('version', 'v1'),
+ ('project', self.project_json)]
+ parsed_args = self.check_parser(project_put, args, verifies)
+ project_put.take_action(parsed_args)
+ self.put_mock.assert_called_once()
diff --git a/testapi/testapi-client/testapiclient/tests/unit/test_scenario_project_client.py b/testapi/testapi-client/testapiclient/tests/unit/test_scenario_project_client.py
new file mode 100644
index 0000000..f8c3d60
--- /dev/null
+++ b/testapi/testapi-client/testapiclient/tests/unit/test_scenario_project_client.py
@@ -0,0 +1,104 @@
+import json
+
+from six.moves.urllib import parse
+import testtools
+
+from testapiclient.client import scenarios
+from testapiclient.tests.unit import fakes
+from testapiclient.tests.unit import utils
+
+
+class ProjectClientTest(utils.TestCommand):
+ def setUp(self):
+ super(ProjectClientTest, self).setUp()
+ self.scenario_name = 'scenrio1'
+ self.base_url = parse.urljoin(
+ self.api_url,
+ 'scenarios/{}/projects'.format(self.scenario_name))
+ self.project_json = {
+ 'trust_indicators': [],
+ 'project': 'test-project',
+ 'scores': [],
+ 'customs': []
+ }
+ self.installer_name = 'installer'
+ self.version_name = 'version'
+ self.project_client = scenarios.ProjectsClient()
+ self.project_string = json.dumps(self.project_json)
+
+
+class ProjectClientCreateTest(ProjectClientTest):
+
+ def setUp(self):
+ super(ProjectClientCreateTest, self).setUp()
+ self.succ_rsp = {
+ 'href': '{}/{}'.format(
+ self.base_url, self.project_json.get('name'))
+ }
+
+ def test_create_success(self):
+ self.post_mock.return_value = fakes.FakeResponse(
+ data=self.succ_rsp)
+ self.project_client.create(
+ self.scenario_name, self.installer_name,
+ self.version_name, self.project_json)
+ 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
+ self.project_client.create(
+ self.scenario_name, self.installer_name,
+ self.version_name, self.project_json)
+
+
+class ProjectClientDeleteTest(ProjectClientTest):
+
+ def setUp(self):
+ super(ProjectClientDeleteTest, self).setUp()
+
+ def test_delete_success(self):
+ self.delete_mock.return_value = fakes.FakeResponse()
+ self.project_client.delete(
+ self.scenario_name, self.installer_name,
+ self.version_name, 'def')
+ kall = self.delete_mock.call_args
+ args, kwargs = kall
+ self.assert_url(
+ args[0],
+ self.base_url + '?installer=installer&version=version')
+
+ def test_delete_failure(self):
+ with testtools.ExpectedException(Exception, 'Delete failed: Error'):
+ self.delete_mock.return_value = utils.FAKE_FAILURE
+ self.project_client.delete(
+ self.scenario_name, self.installer_name,
+ self.version_name, 'def')
+
+
+class ProjectClientUpdateTest(ProjectClientTest):
+
+ def setUp(self):
+ super(ProjectClientUpdateTest, self).setUp()
+
+ def test_update_success(self):
+ self.put_mock.return_value = fakes.FakeResponse()
+ self.project_client.update(
+ self.scenario_name,
+ self.installer_name,
+ self.version_name,
+ self.project_json)
+ kall = self.put_mock.call_args
+ args, kwargs = kall
+ self.assert_url(
+ args[0],
+ self.base_url + '?installer=installer&version=version')
+
+ def test_update_failure(self):
+ with testtools.ExpectedException(Exception, 'Update failed: Error'):
+ self.put_mock.return_value = utils.FAKE_FAILURE
+ self.project_client.update(
+ self.scenario_name,
+ self.installer_name,
+ self.version_name,
+ self.project_json)
diff --git a/testapi/testapi-client/testapiclient/tests/unit/test_scenario_score.py b/testapi/testapi-client/testapiclient/tests/unit/test_scenario_score.py
new file mode 100644
index 0000000..3b0e1c6
--- /dev/null
+++ b/testapi/testapi-client/testapiclient/tests/unit/test_scenario_score.py
@@ -0,0 +1,42 @@
+import json
+
+from mock import mock
+from six.moves.urllib import parse
+
+from testapiclient.cli import scenarios
+from testapiclient.tests.unit import fakes
+from testapiclient.tests.unit import utils
+
+
+class ScoreTest(utils.TestCommand):
+ def setUp(self):
+ super(ScoreTest, self).setUp()
+ self.base_url = parse.urljoin(self.api_url, 'scenarios/{}/scores')
+ self.scenario_name = 's1'
+ self.score_json = {
+ 'score': 'test_score1',
+ 'date': '2018/01/2'
+ }
+ self.score_string = json.dumps(self.score_json)
+
+
+class ScoreCreateTest(ScoreTest):
+
+ def setUp(self):
+ super(ScoreCreateTest, self).setUp()
+
+ def test_create_success(self):
+ self.post_mock.return_value = fakes.FakeResponse(data=None)
+ score_create = scenarios.ScoreCreate(self.app, mock.Mock())
+ args = [
+ '--scenario-name', 's1', '--installer', 'i1', '--version', 'v1',
+ '--project', 'p1', self.score_string]
+ verifies = [
+ ('scenario_name', 's1'),
+ ('installer', 'i1'),
+ ('version', 'v1'),
+ ('project', 'p1'),
+ ('score', self.score_json)]
+ parsed_args = self.check_parser(score_create, args, verifies)
+ score_create.take_action(parsed_args)
+ self.post_mock.assert_called_once()
diff --git a/testapi/testapi-client/testapiclient/tests/unit/test_scenario_score_client.py b/testapi/testapi-client/testapiclient/tests/unit/test_scenario_score_client.py
new file mode 100644
index 0000000..beebd47
--- /dev/null
+++ b/testapi/testapi-client/testapiclient/tests/unit/test_scenario_score_client.py
@@ -0,0 +1,53 @@
+import json
+
+from six.moves.urllib import parse
+import testtools
+
+from testapiclient.client import scenarios
+from testapiclient.tests.unit import fakes
+from testapiclient.tests.unit import utils
+
+
+class ScoreClientTest(utils.TestCommand):
+ def setUp(self):
+ super(ScoreClientTest, self).setUp()
+ self.scenario_name = 'scenrio1'
+ self.base_url = parse.urljoin(
+ self.api_url,
+ 'scenarios/{}/scores'.format(self.scenario_name))
+ self.score_json = {
+ 'score': 'test_score1',
+ 'date': '2018/01/2'
+ }
+ self.installer_name = 'installer'
+ self.version_name = 'version'
+ self.project_name = 'project'
+ self.score_client = scenarios.ScoresClient()
+ self.score_string = json.dumps(self.score_json)
+
+
+class ScoreClientCreateTest(ScoreClientTest):
+
+ def setUp(self):
+ super(ScoreClientCreateTest, self).setUp()
+ self.succ_rsp = {
+ 'href': '{}/{}'.format(
+ self.base_url, self.score_json.get('name'))
+ }
+
+ def test_create_success(self):
+ self.post_mock.return_value = fakes.FakeResponse(
+ data=self.succ_rsp)
+ self.score_client.create(
+ self.scenario_name, self.installer_name,
+ self.version_name, self.project_name,
+ self.score_json)
+ 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
+ self.score_client.create(
+ self.scenario_name, self.installer_name,
+ self.version_name, self.project_name,
+ self.score_json)
diff --git a/testapi/testapi-client/testapiclient/tests/unit/test_scenario_trust_indicator.py b/testapi/testapi-client/testapiclient/tests/unit/test_scenario_trust_indicator.py
new file mode 100644
index 0000000..04be30c
--- /dev/null
+++ b/testapi/testapi-client/testapiclient/tests/unit/test_scenario_trust_indicator.py
@@ -0,0 +1,45 @@
+import json
+
+from mock import mock
+from six.moves.urllib import parse
+
+from testapiclient.cli import scenarios
+from testapiclient.tests.unit import fakes
+from testapiclient.tests.unit import utils
+
+
+class TrustIndicatorTest(utils.TestCommand):
+ def setUp(self):
+ super(TrustIndicatorTest, self).setUp()
+ self.base_url = parse.urljoin(
+ self.api_url,
+ 'scenarios/{}/trustindicators'
+ )
+ self.scenario_name = 's1'
+ self.trust_indicator_json = {
+ 'status': 'test_status',
+ 'date': '2018/01/2'
+ }
+ self.trust_indicator_string = json.dumps(self.trust_indicator_json)
+
+
+class TrustIndicatorCreateTest(TrustIndicatorTest):
+
+ def setUp(self):
+ super(TrustIndicatorCreateTest, self).setUp()
+
+ def test_create_success(self):
+ self.post_mock.return_value = fakes.FakeResponse(data=None)
+ ti_create = scenarios.TrustIndicatorCreate(self.app, mock.Mock())
+ args = [
+ '--scenario-name', 's1', '--installer', 'i1', '--version', 'v1',
+ '--project', 'p1', self.trust_indicator_string]
+ verifies = [
+ ('scenario_name', 's1'),
+ ('installer', 'i1'),
+ ('version', 'v1'),
+ ('project', 'p1'),
+ ('trust_indicator', self.trust_indicator_json)]
+ parsed_args = self.check_parser(ti_create, args, verifies)
+ ti_create.take_action(parsed_args)
+ self.post_mock.assert_called_once()
diff --git a/testapi/testapi-client/testapiclient/tests/unit/test_scenario_trust_indicator_client.py b/testapi/testapi-client/testapiclient/tests/unit/test_scenario_trust_indicator_client.py
new file mode 100644
index 0000000..e44e2d2
--- /dev/null
+++ b/testapi/testapi-client/testapiclient/tests/unit/test_scenario_trust_indicator_client.py
@@ -0,0 +1,53 @@
+import json
+
+from six.moves.urllib import parse
+import testtools
+
+from testapiclient.client import scenarios
+from testapiclient.tests.unit import fakes
+from testapiclient.tests.unit import utils
+
+
+class TrustIndicatorClientTest(utils.TestCommand):
+ def setUp(self):
+ super(TrustIndicatorClientTest, self).setUp()
+ self.scenario_name = 'scenrio1'
+ self.base_url = parse.urljoin(
+ self.api_url,
+ 'scenarios/{}/trust_indicators'.format(self.scenario_name))
+ self.trust_indicator_json = {
+ 'status': 'test_status',
+ 'date': '2018/01/2'
+ }
+ self.installer_name = 'installer'
+ self.version_name = 'version'
+ self.project_name = 'project'
+ self.trust_indicator_client = scenarios.TrustIndicatorsClient()
+ self.trust_indicator_string = json.dumps(self.trust_indicator_json)
+
+
+class TrustIndicatorClientCreateTest(TrustIndicatorClientTest):
+
+ def setUp(self):
+ super(TrustIndicatorClientCreateTest, self).setUp()
+ self.succ_rsp = {
+ 'href': '{}/{}'.format(
+ self.base_url, self.trust_indicator_json.get('name'))
+ }
+
+ def test_create_success(self):
+ self.post_mock.return_value = fakes.FakeResponse(
+ data=self.succ_rsp)
+ self.trust_indicator_client.create(
+ self.scenario_name, self.installer_name,
+ self.version_name, self.project_name,
+ self.trust_indicator_json)
+ 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
+ self.trust_indicator_client.create(
+ self.scenario_name, self.installer_name,
+ self.version_name, self.project_name,
+ self.trust_indicator_json)
diff --git a/testapi/testapi-client/testapiclient/tests/unit/test_scenario_version.py b/testapi/testapi-client/testapiclient/tests/unit/test_scenario_version.py
new file mode 100644
index 0000000..280e9a6
--- /dev/null
+++ b/testapi/testapi-client/testapiclient/tests/unit/test_scenario_version.py
@@ -0,0 +1,107 @@
+import json
+
+from mock import mock
+from six.moves.urllib import parse
+
+from testapiclient.cli import scenarios
+from testapiclient.tests.unit import fakes
+from testapiclient.tests.unit import utils
+from testapiclient.utils import clientmanager
+
+
+class VersionTest(utils.TestCommand):
+ def setUp(self):
+ super(VersionTest, self).setUp()
+ self.base_url = parse.urljoin(self.api_url, 'scenarios/{}/versions')
+ self.scenario_name = 's1'
+ self.version_json = {
+ 'projects': [],
+ 'version': 'test-version',
+ 'owner': 'test_owner'
+ }
+ self.version_string = json.dumps(self.version_json)
+
+
+class VersionCreateTest(VersionTest):
+
+ def setUp(self):
+ super(VersionCreateTest, self).setUp()
+
+ def test_create_success(self):
+ self.post_mock.return_value = fakes.FakeResponse(data=None)
+ version_create = scenarios.VersionCreate(self.app, mock.Mock())
+ args = [
+ '--scenario-name', 's1', '--installer', 'i1', self.version_string]
+ verifies = [
+ ('scenario_name', 's1'),
+ ('installer', 'i1'),
+ ('version', self.version_json)]
+ parsed_args = self.check_parser(version_create, args, verifies)
+ version_create.take_action(parsed_args)
+ self.post_mock.assert_called_once()
+
+
+class VersionDeleteTest(VersionTest):
+
+ def setUp(self):
+ super(VersionDeleteTest, self).setUp()
+
+ def test_delete_success(self):
+ self.delete_mock.return_value = fakes.FakeResponse(data=None)
+ version_delete = scenarios.VersionDelete(self.app, mock.Mock())
+ args = ['--scenario-name', 's1', '--installer', 'i1', 'def']
+ verifies = [
+ ('scenario_name', 's1'),
+ ('installer', 'i1'),
+ ('name', ['def'])]
+ parsed_args = self.check_parser(version_delete, args, verifies)
+ version_delete.take_action(parsed_args)
+ self.delete_mock.assert_called_once_with(
+ self.base_url.format(parsed_args.scenario_name) + '?installer=i1',
+ data=json.dumps(['def']),
+ headers=clientmanager.ClientManager.headers)
+
+
+class VersionPutTest(VersionTest):
+
+ def setUp(self):
+ super(VersionPutTest, self).setUp()
+
+ def test_put_success(self):
+ self.put_mock.return_value = fakes.FakeResponse(
+ data=None)
+ version_put = scenarios.VersionPut(self.app, mock.Mock())
+ args = [
+ '--scenario-name', 's1', '--installer', 'i1', self.version_string]
+ verifies = [
+ ('scenario_name', 's1'),
+ ('installer', 'i1'),
+ ('version', self.version_json)]
+ parsed_args = self.check_parser(version_put, args, verifies)
+ version_put.take_action(parsed_args)
+ self.put_mock.assert_called_once()
+
+
+class VersionOwnerPutTest(VersionTest):
+
+ def setUp(self):
+ super(VersionOwnerPutTest, self).setUp()
+
+ def test_put_success(self):
+ self.put_mock.return_value = fakes.FakeResponse(
+ data=None)
+ version_put = scenarios.VersionOwnerPut(self.app, mock.Mock())
+ version_owner = {
+ 'owner': 'test_owner'
+ }
+ args = [
+ '--scenario-name', 's1', '--installer', 'i1',
+ '--version', 'v1', json.dumps(version_owner)]
+ verifies = [
+ ('scenario_name', 's1'),
+ ('installer', 'i1'),
+ ('version', 'v1'),
+ ('owner', version_owner)]
+ parsed_args = self.check_parser(version_put, args, verifies)
+ version_put.take_action(parsed_args)
+ self.put_mock.assert_called_once()
diff --git a/testapi/testapi-client/testapiclient/tests/unit/test_scenario_version_client.py b/testapi/testapi-client/testapiclient/tests/unit/test_scenario_version_client.py
new file mode 100644
index 0000000..1ae2409
--- /dev/null
+++ b/testapi/testapi-client/testapiclient/tests/unit/test_scenario_version_client.py
@@ -0,0 +1,96 @@
+import json
+
+from six.moves.urllib import parse
+import testtools
+
+from testapiclient.client import scenarios
+from testapiclient.tests.unit import fakes
+from testapiclient.tests.unit import utils
+from testapiclient.utils import clientmanager
+
+
+class VersionClientTest(utils.TestCommand):
+ def setUp(self):
+ super(VersionClientTest, self).setUp()
+ self.scenario_name = 'scenrio1'
+ self.base_url = parse.urljoin(
+ self.api_url,
+ 'scenarios/{}/versions'.format(self.scenario_name))
+ self.version_json = {
+ 'projects': [],
+ 'version': 'test-version',
+ 'owner': 'test_owner'
+ }
+ self.installer_name = 'installer'
+ self.version_client = scenarios.VersionsClient()
+ self.version_string = json.dumps(self.version_json)
+
+
+class VersionClientCreateTest(VersionClientTest):
+
+ def setUp(self):
+ super(VersionClientCreateTest, self).setUp()
+ self.succ_rsp = {
+ 'href': '{}/{}'.format(
+ self.base_url, self.version_json.get('name'))
+ }
+
+ def test_create_success(self):
+ self.post_mock.return_value = fakes.FakeResponse(
+ data=self.succ_rsp)
+ self.version_client.create(
+ self.scenario_name, self.installer_name, self.version_json)
+ 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
+ self.version_client.create(
+ self.scenario_name, self.installer_name, self.version_json)
+
+
+class VersionClientDeleteTest(VersionClientTest):
+
+ def setUp(self):
+ super(VersionClientDeleteTest, self).setUp()
+
+ def test_delete_success(self):
+ self.delete_mock.return_value = fakes.FakeResponse()
+ self.version_client.delete(
+ self.scenario_name, self.installer_name, 'def')
+ kall = self.delete_mock.call_args
+ args, kwargs = kall
+ self.assert_url(
+ args[0],
+ self.base_url + '?installer=installer')
+
+ def test_delete_failure(self):
+ with testtools.ExpectedException(Exception, 'Delete failed: Error'):
+ self.delete_mock.return_value = utils.FAKE_FAILURE
+ self.version_client.delete(
+ self.scenario_name, self.installer_name, 'def')
+
+
+class VersionClientUpdateTest(VersionClientTest):
+
+ def setUp(self):
+ super(VersionClientUpdateTest, self).setUp()
+
+ def test_update_success(self):
+ self.put_mock.return_value = fakes.FakeResponse()
+ self.version_client.update(
+ self.scenario_name,
+ self.installer_name,
+ self.version_json)
+ self.put_mock.assert_called_once_with(
+ self.base_url + '?installer=installer',
+ data=self.version_string,
+ headers=clientmanager.ClientManager.headers)
+
+ def test_update_failure(self):
+ with testtools.ExpectedException(Exception, 'Update failed: Error'):
+ self.put_mock.return_value = utils.FAKE_FAILURE
+ self.version_client.update(
+ self.scenario_name,
+ self.installer_name,
+ self.version_json)
diff --git a/testapi/testapi-client/testapiclient/tests/unit/test_testcase_client.py b/testapi/testapi-client/testapiclient/tests/unit/test_testcase_client.py
new file mode 100644
index 0000000..d80ae27
--- /dev/null
+++ b/testapi/testapi-client/testapiclient/tests/unit/test_testcase_client.py
@@ -0,0 +1,118 @@
+import json
+
+from six.moves.urllib import parse
+import testtools
+
+from testapiclient.client import testcases
+from testapiclient.tests.unit import fakes
+from testapiclient.tests.unit import utils
+from testapiclient.utils import clientmanager
+
+
+class TestcaseClientTest(utils.TestCommand):
+ def setUp(self):
+ super(TestcaseClientTest, 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_client = testcases.TestcasesClient()
+ self.testcase_string = json.dumps(self.testcase_json)
+
+
+class TestcaseClientGetTest(TestcaseClientTest):
+
+ def setUp(self):
+ super(TestcaseClientGetTest, self).setUp()
+ self.testcases_rsp = {'testcases': [self.testcase_json]}
+
+ def test_get(self):
+ self.get_mock.return_value = fakes.FakeResponse(
+ data=self.testcases_rsp)
+ self.testcase_client.get(self.project_name)
+ self.get_mock.assert_called_once_with(
+ self.base_url.format(self.project_name),
+ headers=clientmanager.ClientManager.headers)
+
+ def test_get_one(self):
+ self.get_mock.return_value = fakes.FakeResponse(
+ data=self.testcase_json)
+ self.testcase_client.get_one(self.project_name, 'def')
+ self.get_mock.assert_called_once_with(
+ self.base_url.format(self.project_name) + '/def',
+ headers=clientmanager.ClientManager.headers)
+
+
+class TestcaseClientCreateTest(TestcaseClientTest):
+
+ def setUp(self):
+ super(TestcaseClientCreateTest, self).setUp()
+ self.succ_rsp = {
+ 'href': '{}/{}'.format(
+ self.base_url, self.testcase_json.get('name'))
+ }
+
+ def test_create_success(self):
+ self.post_mock.return_value = fakes.FakeResponse(
+ data=self.succ_rsp)
+ self.testcase_client.create(self.project_name, self.testcase_json)
+ 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
+ self.testcase_client.create(self.project_name, self.testcase_json)
+
+
+class TestcaseClientDeleteTest(TestcaseClientTest):
+
+ def setUp(self):
+ super(TestcaseClientDeleteTest, self).setUp()
+
+ def test_delete_success(self):
+ self.delete_mock.return_value = fakes.FakeResponse()
+ self.testcase_client.delete(self.project_name, 'def')
+ self.delete_mock.assert_called_once_with(
+ self.base_url.format(self.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
+ self.testcase_client.delete(self.project_name, 'def')
+
+
+class TestcaseClientUpdateTest(TestcaseClientTest):
+
+ def setUp(self):
+ super(TestcaseClientUpdateTest, self).setUp()
+
+ def test_update_success(self):
+ self.put_mock.return_value = fakes.FakeResponse()
+ self.testcase_client.update(
+ self.project_name, 'def', self.testcase_json)
+ self.put_mock.assert_called_once_with(
+ self.base_url.format(self.project_name) + '/def',
+ data=self.testcase_string,
+ headers=clientmanager.ClientManager.headers)
+
+ def test_update_failure(self):
+ with testtools.ExpectedException(Exception, 'Update failed: Error'):
+ self.put_mock.return_value = utils.FAKE_FAILURE
+ self.testcase_client.update(
+ self.project_name, 'def', self.testcase_json)
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/tests/unit/utils.py b/testapi/testapi-client/testapiclient/tests/unit/utils.py
index 20f9a47..c59aadd 100644
--- a/testapi/testapi-client/testapiclient/tests/unit/utils.py
+++ b/testapi/testapi-client/testapiclient/tests/unit/utils.py
@@ -1,6 +1,7 @@
import httplib
from mock import mock
+from six.moves.urllib import parse
import testtools
from testapiclient.tests.unit import fakes
@@ -18,7 +19,7 @@ class TestCommand(testtools.TestCase):
def setUp(self):
super(TestCommand, self).setUp()
- env_variables = {
+ self.env_variables = {
'testapi_url': 'http://localhost:8000/api/v1',
'testapi_cas_auth_url':
(
@@ -28,7 +29,7 @@ class TestCommand(testtools.TestCase):
'testapi_cas_signin_return': '/auth/signin_return'
}
self.config_mock = mock.patch.dict(
- 'os.environ', env_variables).start()
+ 'os.environ', self.env_variables).start()
self.fake_stdout = fakes.FakeStdout()
self.fake_log = fakes.FakeLog()
self.app = fakes.FakeApp(self.fake_stdout, self.fake_log)
@@ -50,3 +51,8 @@ class TestCommand(testtools.TestCase):
self.assertIn(attr, parsed_args)
self.assertEqual(value, getattr(parsed_args, attr))
return parsed_args
+
+ 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
diff --git a/testapi/testapi-client/testapiclient/utils/clientmanager.py b/testapi/testapi-client/testapiclient/utils/clientmanager.py
index 4401231..cbfd723 100644
--- a/testapi/testapi-client/testapiclient/utils/clientmanager.py
+++ b/testapi/testapi-client/testapiclient/utils/clientmanager.py
@@ -10,7 +10,9 @@ LOG = logging.getLogger(__name__)
class ClientManager(object):
- headers = {'Content-type': 'application/json', 'Accept': 'text/plain'}
+ headers = {
+ 'Content-type': 'application/json',
+ 'Accept': 'text/plain'}
def __init__(self, cli_options=None):
self.cli_options = cli_options
@@ -49,6 +51,8 @@ class ClientManager(object):
headers=self.headers))
def post(self, url, data):
+ if 'results' in url or 'deployresults' in url:
+ self.headers['X-Auth-Token'] = os.environ.get('testapi_token')
return self._parse_response('Create',
self._request('post', url,
data=json.dumps(data),
@@ -75,6 +79,9 @@ class ClientManager(object):
def _parse_response(self, op, response):
if response.status_code == httplib.OK:
- return response.json() if op != 'Delete' else None
+ if op != 'Delete' and response.text != '':
+ return response.json()
+ else:
+ return None
else:
self._raise_failure(op, response)
diff --git a/testapi/testapi-client/testapiclient/utils/command.py b/testapi/testapi-client/testapiclient/utils/command.py
index 9614acf..b9d1ce8 100644
--- a/testapi/testapi-client/testapiclient/utils/command.py
+++ b/testapi/testapi-client/testapiclient/utils/command.py
@@ -20,17 +20,6 @@ class CommandMeta(abc.ABCMeta):
@six.add_metaclass(CommandMeta)
class Command(command.Command):
-
- def get_parser(self, prog_name):
- parser = super(Command, self).get_parser(prog_name)
- parser.add_argument('-u',
- type=str,
- help='Username for authentication')
- parser.add_argument('-p',
- type=str,
- help='Password for authentication')
- return parser
-
def run(self, parsed_args):
self.log.debug('run(%s)', parsed_args)
return super(Command, self).run(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):
diff --git a/testapi/tox.ini b/testapi/tox.ini
index e15deea..0478e23 100644
--- a/testapi/tox.ini
+++ b/testapi/tox.ini
@@ -14,6 +14,8 @@ install_command = pip install -U {opts} {packages}
deps =
-rrequirements.txt
-rtest-requirements.txt
+ -chttps://raw.githubusercontent.com/openstack/requirements/stable/ussuri/upper-constraints.txt
+ -cupper-constraints.txt
commands=
py.test \
--basetemp={envtmpdir} \
@@ -30,18 +32,21 @@ basepython=python2.7
commands = sphinx-build -W -b html docs/ docs/_build
[testenv:pep8]
+basepython=python2.7
deps = flake8
commands = flake8 {toxinidir}
[flake8]
+basepython=python2.7
# H803 skipped on purpose per list discussion.
# E123, E125 skipped as they are invalid PEP-8.
show-source = True
-ignore = E123,E125,H803
+ignore = E123,E125,H803,W503,W504
builtins = _
exclude = build,dist,doc,legacy,.eggs,.git,.tox,.venv,testapi_venv,venv
[pytest]
+basepython=python2.7
testpaths = opnfv_testapi/tests
python_functions = test_*
diff --git a/testapi/upper-constraints.txt b/testapi/upper-constraints.txt
new file mode 100644
index 0000000..5226f48
--- /dev/null
+++ b/testapi/upper-constraints.txt
@@ -0,0 +1,9 @@
+epydoc===3.0.1
+motor===1.2.2
+python-cas===1.2.0
+argparse===1.2.1
+backports-abc===0.5
+backports.ssl-match-hostname===3.5.0.1
+html5lib===0.999
+singledispatch===3.4.0.3
+wsgiref===0.1.2