summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--reporting/3rd_party/html/gambia.html141
-rw-r--r--reporting/3rd_party/html/index.html16
-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.sh7
-rw-r--r--reporting/img/gambia.jpgbin0 -> 45206 bytes
-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
-rwxr-xr-xreporting/reporting/functest/reporting-status.py123
-rw-r--r--reporting/reporting/functest/template/index-status-tmpl.html25
-rw-r--r--reporting/reporting/functest/testCase.py73
-rw-r--r--reporting/reporting/reporting.yaml6
-rw-r--r--reporting/reporting/vsperf/reporting-status.py2
-rw-r--r--testapi/docker/Dockerfile43
-rwxr-xr-xtestapi/docker/prepare-env.sh24
-rw-r--r--testapi/opnfv_testapi/tests/unit/executor.py6
-rw-r--r--testapi/opnfv_testapi/tests/unit/fake_pymongo.py6
-rw-r--r--testapi/opnfv_testapi/ui/Gruntfile.js1
-rw-r--r--testapi/requirements.txt17
-rw-r--r--testapi/setup.py22
-rw-r--r--testapi/test-requirements.txt12
-rw-r--r--testapi/tox.ini7
-rw-r--r--testapi/upper-constraints.txt9
34 files changed, 852 insertions, 195 deletions
diff --git a/reporting/3rd_party/html/gambia.html b/reporting/3rd_party/html/gambia.html
new file mode 100644
index 0000000..d5f6fcd
--- /dev/null
+++ b/reporting/3rd_party/html/gambia.html
@@ -0,0 +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>
+
+ </div>
+ </header>
+
+ <!-- Menu -->
+ <!-- Main -->
+ <div id="main">
+ <div class="inner">
+ <header>
+ <h1>Gambia reporting</h1>
+ </header>
+ <section class="tiles">
+ <article class="style3">
+ <span class="image">
+ <img src="img/projectIcon_functest_250x250.png" alt="" />
+ </span>
+ <a href="gambia/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="gambia/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="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/projectIcon_bottlenecks_250x250.png" alt="" />
+ </span>
+ <a href="gambia/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/3rd_party/html/index.html b/reporting/3rd_party/html/index.html
index 858ac47..9165250 100644
--- a/reporting/3rd_party/html/index.html
+++ b/reporting/3rd_party/html/index.html
@@ -45,23 +45,23 @@
<section class="tiles">
<article class="style4">
<span class="image">
- <img src="img/euphrates.jpg" alt="" />
+ <img src="img/fraser.jpg" alt="" />
</span>
- <a href="euphrates.html">
- <h2>Euphrates</h2>
+ <a href="fraser.html">
+ <h2>Fraser</h2>
<div class="content">
- <p>Euphrates (ETA 10/2017)</p>
+ <p>Fraser (ETA 04/2018)</p>
</div>
</a>
</article>
<article class="style6">
<span class="image">
- <img src="img/fraser.jpg" alt="" />
+ <img src="img/gambia.jpg" alt="" />
</span>
- <a href="fraser.html">
- <h2>Fraser</h2>
+ <a href="gambia.html">
+ <h2>Gambia</h2>
<div class="content">
- <p>Fraser (ETA 04/2018)</p>
+ <p>Gambia (ETA 11/2018)</p>
</div>
</a>
</article>
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 8ca7eac..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=(fraser euphrates master)
+declare -a versions=(gambia fraser master)
declare -a projects=(functest storperf yardstick qtip vsperf bottlenecks)
project=$1
@@ -25,11 +25,6 @@ cp -Rf 3rd_party/html/* display
cp -Rf img display
cp -Rf js display
-for i in "${versions[@]}"
-do
- cp -Rf html/functest.html display/$i/functest
-done
-
# if nothing is precised run all the reporting generation
# projet | option
# $1 | $2
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/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/functest/reporting-status.py b/reporting/reporting/functest/reporting-status.py
index 552080d..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']))
-
-LOGGER.debug("Functest reporting start")
+ dependencies,
+ tier=tier['name']))
+ 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")
+ 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 Exception: # pylint: disable=broad-except
+ 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/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 d114f8a..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,13 +45,14 @@ 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)',
@@ -58,8 +61,29 @@ class TestCase(object):
'odl_netvirt': 'Netvirt',
'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)',
- 'neutron_trunk': 'Neutron trunk'}
+ '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:
@@ -71,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
@@ -101,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 b2f7d07..6a59a44 100644
--- a/reporting/reporting/reporting.yaml
+++ b/reporting/reporting/reporting.yaml
@@ -9,7 +9,7 @@ general:
versions:
- master
- - fraser
+ - 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 f1a437f..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', 'fraser'}:
+ for version in {'master', 'fraser', 'gambia'}:
_generate_reporting(version, version_data.get(version, []))
LOG.info("End")
diff --git a/testapi/docker/Dockerfile b/testapi/docker/Dockerfile
index 86999d9..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 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/opnfv_testapi/tests/unit/executor.py b/testapi/opnfv_testapi/tests/unit/executor.py
index 5a8d688..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():
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/ui/Gruntfile.js b/testapi/opnfv_testapi/ui/Gruntfile.js
index ab59475..d6a2f47 100644
--- a/testapi/opnfv_testapi/ui/Gruntfile.js
+++ b/testapi/opnfv_testapi/ui/Gruntfile.js
@@ -152,6 +152,7 @@ module.exports = function (grunt) {
makeReport: {
src: '../tests/UI/coverage/*.json',
options: {
+ type: 'cobertura',
print: 'detail'
}
}
diff --git a/testapi/requirements.txt b/testapi/requirements.txt
index 7f50fd7..9dba746 100644
--- a/testapi/requirements.txt
+++ b/testapi/requirements.txt
@@ -2,12 +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]
-futures \ 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/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