diff options
Diffstat (limited to 'utils/test')
79 files changed, 2666 insertions, 1535 deletions
diff --git a/utils/test/dashboard/dashboard/functest/testcases.yaml b/utils/test/dashboard/dashboard/functest/testcases.yaml index 9c33d2e6b..85cb8b292 100644 --- a/utils/test/dashboard/dashboard/functest/testcases.yaml +++ b/utils/test/dashboard/dashboard/functest/testcases.yaml @@ -1,3 +1,4 @@ +--- functest: - name: tempest_smoke_serial diff --git a/utils/test/dashboard/dashboard/qtip/testcases.yaml b/utils/test/dashboard/dashboard/qtip/testcases.yaml index cd337cd73..dfa9cc2db 100644 --- a/utils/test/dashboard/dashboard/qtip/testcases.yaml +++ b/utils/test/dashboard/dashboard/qtip/testcases.yaml @@ -1,3 +1,4 @@ +--- qtip: - name: compute_test_suite @@ -18,7 +19,7 @@ qtip: fields: - field: details.index - - name:storage_test_suite + name: storage_test_suite format: qpi test_family: storage visualizations: diff --git a/utils/test/reporting/api/handlers/landing.py b/utils/test/reporting/api/handlers/landing.py index 137c05007..ae1fd2037 100644 --- a/utils/test/reporting/api/handlers/landing.py +++ b/utils/test/reporting/api/handlers/landing.py @@ -6,15 +6,172 @@ # which accompanies this distribution, and is available at # http://www.apache.org/licenses/LICENSE-2.0 ############################################################################## +import requests + from tornado.web import RequestHandler from tornado.escape import json_encode +from tornado.escape import json_decode -class FiltersHandler(RequestHandler): - def get(self): - return self.write(json_encode({'status': 'SUCCESS'})) +class BaseHandler(RequestHandler): + def _set_header(self): + self.set_header('Access-Control-Allow-Origin', '*') + self.set_header('Access-Control-Allow-Headers', + 'Content-Type, Content-Length, Authorization, \ + Accept, X-Requested-With , PRIVATE-TOKEN') + self.set_header('Access-Control-Allow-Methods', + 'PUT, POST, GET, DELETE, OPTIONS') -class ScenariosHandler(RequestHandler): +class FiltersHandler(BaseHandler): def get(self): - return self.write(json_encode({'status': 'SUCCESS'})) + self._set_header() + + filters = { + 'filters': { + 'status': ['success', 'warning', 'danger'], + 'projects': ['functest', 'yardstick'], + 'installers': ['apex', 'compass', 'fuel', 'joid'], + 'version': ['colorado', 'master'], + 'loops': ['daily', 'weekly', 'monthly'], + 'time': ['10 days', '30 days'] + } + } + return self.write(json_encode(filters)) + + +class ScenariosHandler(BaseHandler): + def post(self): + self._set_header() + + body = json_decode(self.request.body) + args = self._get_args(body) + + scenarios = self._get_result_data(self._get_scenarios(), args) + + return self.write(json_encode(dict(scenarios=scenarios))) + + def _get_result_data(self, data, args): + data = self._filter_status(data, args) + return {s: self._get_scenario_result(s, data[s], args) for s in data} + + def _filter_status(self, data, args): + return {k: v for k, v in data.items() if v['status'] in args['status']} + + def _get_scenario_result(self, scenario, data, args): + result = { + 'status': data.get('status'), + 'installers': self._get_installers_result(data['installers'], args) + } + return result + + def _get_installers_result(self, data, args): + func = self._get_installer_result + return {k: func(k, data.get(k, {}), args) for k in args['installers']} + + def _get_installer_result(self, installer, data, args): + projects = data.get(args['version'], []) + return [self._get_project_data(projects, p) for p in args['projects']] + + def _get_project_data(self, projects, project): + atom = { + 'project': project, + 'score': None, + 'status': None + } + for p in projects: + if p['project'] == project: + return p + return atom + + def _get_scenarios(self): + url = 'http://testresults.opnfv.org/test/api/v1/scenarios' + resp = requests.get(url).json() + data = self._change_to_utf8(resp).get('scenarios', {}) + return {a.get('name'): self._get_scenario(a.get('installers', []) + ) for a in data} + + def _get_scenario(self, data): + installers = {a.get('installer'): self._get_installer(a.get('versions', + []) + ) for a in data} + scenario = { + 'status': self._get_status(), + 'installers': installers + } + return scenario + + def _get_status(self): + return 'success' + + def _get_installer(self, data): + return {a.get('version'): self._get_version(a) for a in data} + + def _get_version(self, data): + try: + scores = data.get('score', {}).get('projects')[0] + trusts = data.get('trust_indicator', {}).get('projects')[0] + except (TypeError, IndexError): + return [] + else: + scores = {key: [dict(date=a.get('date')[:10], + score=a.get('score') + ) for a in scores[key]] for key in scores} + trusts = {key: [dict(date=a.get('date')[:10], + status=a.get('status') + ) for a in trusts[key]] for key in trusts} + atom = self._get_atom(scores, trusts) + return [dict(project=k, + score=sorted(atom[k], reverse=True)[0].get('score'), + status=sorted(atom[k], reverse=True)[0].get('status') + ) for k in atom if atom[k]] + + def _get_atom(self, scores, trusts): + s = {k: {a['date']: a['score'] for a in scores[k]} for k in scores} + t = {k: {a['date']: a['status'] for a in trusts[k]} for k in trusts} + return {k: [dict(score=s[k][a], status=t[k][a], data=a + ) for a in s[k] if a in t[k]] for k in s} + + def _change_to_utf8(self, obj): + if isinstance(obj, dict): + return {str(k): self._change_to_utf8(v) for k, v in obj.items()} + elif isinstance(obj, list): + return [self._change_to_utf8(ele) for ele in obj] + else: + try: + new = eval(obj) + if isinstance(new, int): + return obj + return self._change_to_utf8(new) + except (NameError, TypeError, SyntaxError): + return str(obj) + + def _get_args(self, body): + status = self._get_status_args(body) + projects = self._get_projects_args(body) + installers = self._get_installers_args(body) + + args = { + 'status': status, + 'projects': projects, + 'installers': installers, + 'version': body.get('version', 'master').lower(), + 'loops': body.get('loops', 'daily').lower(), + 'time': body.get('times', '10 days')[:2].lower() + } + return args + + def _get_status_args(self, body): + status_all = ['success', 'warning', 'danger'] + status = [a.lower() for a in body.get('status', ['all'])] + return status_all if 'all' in status else status + + def _get_projects_args(self, body): + project_all = ['functest', 'yardstick'] + projects = [a.lower() for a in body.get('projects', ['all'])] + return project_all if 'all' in projects else projects + + def _get_installers_args(self, body): + installer_all = ['apex', 'compass', 'fuel', 'joid'] + installers = [a.lower() for a in body.get('installers', ['all'])] + return installer_all if 'all' in installers else installers diff --git a/utils/test/reporting/api/install.sh b/utils/test/reporting/api/install.sh new file mode 100755 index 000000000..55d6b77ec --- /dev/null +++ b/utils/test/reporting/api/install.sh @@ -0,0 +1,3 @@ +apt-get install -y python-pip +pip install tornado +pip install requests diff --git a/utils/test/reporting/docker/reporting.sh b/utils/test/reporting/docker/reporting.sh index 1bef1b811..1de13ae32 100755 --- a/utils/test/reporting/docker/reporting.sh +++ b/utils/test/reporting/docker/reporting.sh @@ -4,7 +4,7 @@ export PYTHONPATH="${PYTHONPATH}:." export CONFIG_REPORTING_YAML=./reporting.yaml declare -a versions=(colorado master) -declare -a projects=(functest yardstick) +declare -a projects=(functest storperf yardstick) project=$1 reporting_type=$2 @@ -30,6 +30,7 @@ cp -Rf js display # $1 | $2 # functest | status, vims, tempest # yardstick | +# storperf | if [ -z "$1" ]; then echo "********************************" @@ -52,6 +53,13 @@ if [ -z "$1" ]; then echo "********************************" python ./yardstick/reporting-status.py echo "Yardstick reporting status...OK" + + echo "********************************" + echo " Storperf reporting " + echo "********************************" + python ./storperf/reporting-status.py + echo "Storperf reporting status...OK" + else if [ -z "$2" ]; then reporting_type="status" @@ -71,10 +79,4 @@ echo "daemon off;" >> /etc/nginx/nginx.conf # supervisor config cp /home/opnfv/utils/test/reporting/docker/supervisor.conf /etc/supervisor/conf.d/ -# build pages -cd pages ln -s /usr/bin/nodejs /usr/bin/node -npm install -npm install -g grunt bower -bower install --allow-root -grunt build diff --git a/utils/test/reporting/docker/supervisor.conf b/utils/test/reporting/docker/supervisor.conf index 0c2207793..1e0eed9c8 100644 --- a/utils/test/reporting/docker/supervisor.conf +++ b/utils/test/reporting/docker/supervisor.conf @@ -14,3 +14,9 @@ autorestart = true user = root command = service nginx restart autorestart = true + +[program:reporting_angular] +user = root +directory = /home/opnfv/utils/test/reporting/pages +command = bash angular.sh +autorestart = true diff --git a/utils/test/reporting/functest/reporting-status.py b/utils/test/reporting/functest/reporting-status.py index 158ee597b..af1d1d8a5 100755 --- a/utils/test/reporting/functest/reporting-status.py +++ b/utils/test/reporting/functest/reporting-status.py @@ -28,9 +28,9 @@ testValid = [] otherTestCases = [] reportingDate = datetime.datetime.now().strftime("%Y-%m-%d %H:%M") -# init just tempest to get the list of scenarios -# as all the scenarios run Tempest -tempest = tc.TestCase("tempest_smoke_serial", "functest", -1) +# init just connection_check to get the list of scenarios +# as all the scenarios run connection_check +healthcheck = tc.TestCase("connection_check", "functest", -1) # Retrieve the Functest configuration to detect which tests are relevant # according to the installer, scenario @@ -61,13 +61,13 @@ logger.info("*******************************************") # Retrieve test cases of Tier 1 (smoke) config_tiers = functest_yaml_config.get("tiers") -# we consider Tier 1 (smoke),2 (features) +# we consider Tier 0 (Healthcheck), Tier 1 (smoke),2 (features) # to validate scenarios -# Tier > 4 are not used to validate scenarios but we display the results anyway +# 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: + if tier['order'] >= 0 and tier['order'] < 2: for case in tier['testcases']: if case['name'] not in blacklist: testValid.append(tc.TestCase(case['name'], @@ -92,12 +92,20 @@ for version in versions: # For all the installers for installer in installers: # get scenarios - scenario_results = rp_utils.getScenarios(tempest, installer, version) + scenario_results = rp_utils.getScenarios(healthcheck, + installer, + version) scenario_stats = rp_utils.getScenarioStats(scenario_results) items = {} scenario_result_criteria = {} - scenario_file_name = ("./display/" + version + - "/functest/scenario_history.txt") + scenario_directory = "./display/" + version + "/functest/" + scenario_file_name = scenario_directory + "scenario_history.txt" + + # check that the directory exists, if not create it + # (first run on new version) + if not os.path.exists(scenario_directory): + os.makedirs(scenario_directory) + # initiate scenario file if it does not exist if not os.path.isfile(scenario_file_name): with open(scenario_file_name, "a") as my_file: @@ -120,7 +128,9 @@ for version in versions: if len(s_result) > 0: build_tag = s_result[len(s_result)-1]['build_tag'] logger.debug("Build tag: %s" % build_tag) - s_url = s_url = rp_utils.getJenkinsUrl(build_tag) + s_url = rp_utils.getJenkinsUrl(build_tag) + if s_url is None: + s_url = "http://testresultS.opnfv.org/reporting" logger.info("last jenkins url: %s" % s_url) testCases2BeDisplayed = [] # Check if test case is runnable / installer, scenario diff --git a/utils/test/reporting/functest/testCase.py b/utils/test/reporting/functest/testCase.py index df0874e0b..f77136e11 100644 --- a/utils/test/reporting/functest/testCase.py +++ b/utils/test/reporting/functest/testCase.py @@ -27,6 +27,7 @@ class TestCase(object): 'ocl': 'OCL', 'tempest_smoke_serial': 'Tempest (smoke)', 'tempest_full_parallel': 'Tempest (full)', + 'tempest_defcore': 'Tempest (Defcore)', 'rally_sanity': 'Rally (smoke)', 'bgpvpn': 'bgpvpn', 'rally_full': 'Rally (full)', @@ -43,7 +44,10 @@ class TestCase(object): 'parser': 'Parser', 'connection_check': 'Health (connection)', 'api_check': 'Health (api)', - 'snaps_smoke': 'SNAPS'} + 'snaps_smoke': 'SNAPS', + 'snaps_health_check': 'Health (dhcp)', + 'netready': 'Netready', + 'barometer': 'Barometer'} try: self.displayName = display_name_matrix[self.name] except: @@ -122,6 +126,7 @@ class TestCase(object): 'ocl': 'ocl', 'tempest_smoke_serial': 'tempest_smoke_serial', 'tempest_full_parallel': 'tempest_full_parallel', + 'tempest_defcore': 'tempest_defcore', 'rally_sanity': 'rally_sanity', 'bgpvpn': 'bgpvpn', 'rally_full': 'rally_full', @@ -138,8 +143,10 @@ class TestCase(object): 'parser': 'parser-basics', 'connection_check': 'connection_check', 'api_check': 'api_check', - 'snaps_smoke': 'snaps_smoke' - } + 'snaps_smoke': 'snaps_smoke', + 'snaps_health_check': 'snaps_health_check', + 'netready': 'gluon_vping', + 'barometer': 'barometercollectd'} try: return test_match_matrix[self.name] except: diff --git a/utils/test/reporting/html/danube.html b/utils/test/reporting/html/danube.html index 58d6bc0fe..d63e19d90 100644 --- a/utils/test/reporting/html/danube.html +++ b/utils/test/reporting/html/danube.html @@ -1,113 +1,124 @@ -<!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>Danube reporting (Master)</h1>
- </header>
- <section class="tiles">
- <article class="style3">
- <span class="image">
- <img src="img/functest.jpg" alt="" />
- </span>
- <a href="functest-master.html">
- <h2>Functest</h2>
- <div class="content">
- <p>Functional testing</p>
- </div>
- </a>
- </article>
- <article class="style2">
- <span class="image">
- <img src="img/yardstick.jpg" alt="" />
- </span>
- <a href="master/yardstick/status-apex.html">
- <h2>Yardstick</h2>
- <div class="content">
- <p>Qualification and performance testing</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>© 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> + + <!-- 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>Danube reporting</h1> + </header> + <section class="tiles"> + <article class="style3"> + <span class="image"> + <img src="img/functest.jpg" alt="" /> + </span> + <a href="functest-danube.html"> + <h2>Functest</h2> + <div class="content"> + <p>Functional testing</p> + </div> + </a> + </article> + <article class="style2"> + <span class="image"> + <img src="img/yardstick.jpg" alt="" /> + </span> + <a href="danube/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/storperf.jpg" alt="" /> + </span> + <a href="danube/storperf/status-apex.html"> + <h2>Storperf</h2> + <div class="content"> + <p>Storage testing</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>© 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/utils/test/reporting/html/functest-danube.html b/utils/test/reporting/html/functest-danube.html new file mode 100644 index 000000000..ac99cb057 --- /dev/null +++ b/utils/test/reporting/html/functest-danube.html @@ -0,0 +1,124 @@ +<!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="danube/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="danube/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="danube/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>© 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/utils/test/reporting/html/functest-master.html b/utils/test/reporting/html/functest-master.html index 03217a6bd..4b1f76347 100644 --- a/utils/test/reporting/html/functest-master.html +++ b/utils/test/reporting/html/functest-master.html @@ -1,124 +1,124 @@ -<!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/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/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/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>© 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> + + <!-- 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>© 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/utils/test/reporting/html/index.html b/utils/test/reporting/html/index.html index b2b8b46f8..c6627ffe5 100644 --- a/utils/test/reporting/html/index.html +++ b/utils/test/reporting/html/index.html @@ -1,113 +1,124 @@ -<!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>OPNFV reporting</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>OPNFV Testing group reporting</h1>
- </header>
- <section class="tiles">
- <article class="style3">
- <span class="image">
- <img src="img/colorado.jpg" alt="" />
- </span>
- <a href="colorado.html">
- <h2>Colorado</h2>
- <div class="content">
- <p>Colorado 1.0 released on the 22nd of September</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>Master</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>© 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>OPNFV reporting</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>OPNFV Testing group reporting</h1> + </header> + <section class="tiles"> + <article class="style3"> + <span class="image"> + <img src="img/colorado.jpg" alt="" /> + </span> + <a href="colorado.html"> + <h2>Colorado</h2> + <div class="content"> + <p>Colorado 1.0 released on the 22nd of September</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 planned on the 22nd of March</p> + </div> + </a> + </article> + <article class="style6"> + <span class="image"> + <img src="img/euphrates.jpg" alt="" /> + </span> + <a href="master.html"> + <h2>Euphrates</h2> + <div class="content"> + <p>Master</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>© 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/utils/test/reporting/html/master.html b/utils/test/reporting/html/master.html new file mode 100644 index 000000000..438bf2023 --- /dev/null +++ b/utils/test/reporting/html/master.html @@ -0,0 +1,124 @@ +<!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>Master reporting</h1> + </header> + <section class="tiles"> + <article class="style3"> + <span class="image"> + <img src="img/functest.jpg" alt="" /> + </span> + <a href="functest-master.html"> + <h2>Functest</h2> + <div class="content"> + <p>Functional testing</p> + </div> + </a> + </article> + <article class="style2"> + <span class="image"> + <img src="img/yardstick.jpg" alt="" /> + </span> + <a href="master/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/storperf.jpg" alt="" /> + </span> + <a href="master/storperf/status-apex.html"> + <h2>Storperf</h2> + <div class="content"> + <p>Storage testing</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>© 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/utils/test/reporting/img/euphrates.jpg b/utils/test/reporting/img/euphrates.jpg Binary files differnew file mode 100644 index 000000000..3625b50cb --- /dev/null +++ b/utils/test/reporting/img/euphrates.jpg diff --git a/utils/test/reporting/img/storperf.jpg b/utils/test/reporting/img/storperf.jpg Binary files differnew file mode 100644 index 000000000..37492e69e --- /dev/null +++ b/utils/test/reporting/img/storperf.jpg diff --git a/utils/test/reporting/pages/angular.sh b/utils/test/reporting/pages/angular.sh new file mode 100755 index 000000000..a7f167516 --- /dev/null +++ b/utils/test/reporting/pages/angular.sh @@ -0,0 +1,10 @@ +: ${SERVER_URL:='http://testresults.opnfv.org/reporting/api'} + +echo "var BASE_URL = 'http://${SERVER_URL}/landing-page'" > app/scripts/app.config.js + +apt-get install -y nodejs +apt-get install -y npm +npm install +npm install -g grunt bower +bower install --allow-root +grunt build diff --git a/utils/test/reporting/pages/app/images/green.png b/utils/test/reporting/pages/app/images/green.png Binary files differnew file mode 100644 index 000000000..57fc59927 --- /dev/null +++ b/utils/test/reporting/pages/app/images/green.png diff --git a/utils/test/reporting/pages/app/images/green@2x.png b/utils/test/reporting/pages/app/images/green@2x.png Binary files differnew file mode 100644 index 000000000..3bda5beb6 --- /dev/null +++ b/utils/test/reporting/pages/app/images/green@2x.png diff --git a/utils/test/reporting/pages/app/index.html b/utils/test/reporting/pages/app/index.html index 7673a4cc2..1159c2176 100644 --- a/utils/test/reporting/pages/app/index.html +++ b/utils/test/reporting/pages/app/index.html @@ -1,6 +1,7 @@ <!doctype html> <html ng-app="opnfvApp"> - <head> + +<head> <meta charset="utf-8"> <title>OPNFV-DASHBOARD EXAMPLE</title> <meta name="description" content=""> @@ -13,17 +14,22 @@ <link rel="stylesheet" href="bower_components/chosen/chosen.css" /> <link rel="stylesheet" href="bower_components/selectize/dist/css/selectize.css" /> <link rel="stylesheet" href="bower_components/components-font-awesome/css/font-awesome.css" /> + <link rel="stylesheet" href="bower_components/angular-tooltips/dist/angular-tooltips.min.css" /> + <link rel="stylesheet" href="bower_components/animate.css/animate.css" /> + <link rel="stylesheet" href="bower_components/ng-dialog/css/ngDialog.css" /> + <link rel="stylesheet" href="bower_components/ng-dialog/css/ngDialog-theme-default.css" /> + <link rel="stylesheet" href="bower_components/inspiniacss/style.css" /> <!-- endbower --> <!-- endbuild --> <!-- build:css(.tmp) styles/style.css --> - <!--<link rel="stylesheet" href="styles/main.css">--> - <link rel="stylesheet" href="styles/animate.css"> - <link rel="stylesheet" href="styles/style.css"> + <link rel="stylesheet" href="styles/custome.css"> + <!-- endbuild --> - </head> - <body class="{{$state.current.data.specialClass}}" id="page-top"> +</head> + +<body class="{{$state.current.data.specialClass}}" id="page-top"> <!--[if lte IE 8]> <p class="browsehappy">You are using an <strong>outdated</strong> browser. Please <a href="http://browsehappy.com/">upgrade your browser</a> to improve your experience.</p> <![endif]--> @@ -31,7 +37,7 @@ <!-- Add your site or application content here --> <div ui-view></div> <!-- Google Analytics: change UA-XXXXX-X to be your site's ID --> - <!--<script> + <!--<script> !function(A,n,g,u,l,a,r){A.GoogleAnalyticsObject=l,A[l]=A[l]||function(){ (A[l].q=A[l].q||[]).push(arguments)},A[l].l=+new Date,a=n.createElement(g), r=n.getElementsByTagName(g)[0],a.src=u,r.parentNode.insertBefore(a,r) @@ -59,17 +65,27 @@ <script src="bower_components/microplugin/src/microplugin.js"></script> <script src="bower_components/selectize/dist/js/selectize.js"></script> <script src="bower_components/angular-selectize2/dist/angular-selectize.js"></script> + <script src="bower_components/angular-tooltips/dist/angular-tooltips.min.js"></script> + <script src="bower_components/jQuery-rwdImageMaps/jquery.rwdImageMaps.min.js"></script> + <script src="bower_components/ng-dialog/js/ngDialog.js"></script> <!-- endbower --> <!-- endbuild --> - <!-- build:js({.tmp,app}) scripts/scripts.js --> - <script src="scripts/app.js"></script> - <!--<script src="scripts/controllers/main.js"></script>--> - <script src="scripts/config.router.js"></script> - <script src="scripts/controllers/table.controller.js"></script> - <script src="scripts/config.js"></script> - <script src="scripts/directives/mydirective.js"></script> - <script src="scripts/factory/table.factory.js"></script> - <!-- endbuild --> + <!-- build:js({.tmp,app}) scripts/scripts.js --> + <script src="scripts/app.js"></script> + <!--<script src="scripts/controllers/main.js"></script>--> + <script src="scripts/config.router.js"></script> + <script src="scripts/controllers/table.controller.js"></script> + <script src="scripts/config.js"></script> + <script src="scripts/factory/table.factory.js"></script> + <script src="scripts/controllers/case.controller.js"></script> + <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/app.config.js"></script> + <script src="scripts/controllers/testvisual.controller.js"></script> + + <!-- endbuild --> </body> -</html> + +</html>
\ No newline at end of file diff --git a/utils/test/reporting/pages/app/scripts/app.config.js b/utils/test/reporting/pages/app/scripts/app.config.js new file mode 100644 index 000000000..e69de29bb --- /dev/null +++ b/utils/test/reporting/pages/app/scripts/app.config.js diff --git a/utils/test/reporting/pages/app/scripts/app.js b/utils/test/reporting/pages/app/scripts/app.js index 6e99ce3d7..d06019c55 100644 --- a/utils/test/reporting/pages/app/scripts/app.js +++ b/utils/test/reporting/pages/app/scripts/app.js @@ -9,12 +9,13 @@ * Main module of the application. */ angular - .module('opnfvApp', [ - 'ngAnimate', - 'ui.router', - 'oc.lazyLoad', - 'ui.bootstrap', - 'ngResource', - 'selectize' + .module('opnfvApp', [ + 'ngAnimate', + 'ui.router', + 'oc.lazyLoad', + 'ui.bootstrap', + 'ngResource', + 'selectize', + '720kb.tooltips' - ]); + ]);
\ No newline at end of file diff --git a/utils/test/reporting/pages/app/scripts/config.js b/utils/test/reporting/pages/app/scripts/config.js index 838460a38..1010169d3 100644 --- a/utils/test/reporting/pages/app/scripts/config.js +++ b/utils/test/reporting/pages/app/scripts/config.js @@ -7,8 +7,13 @@ * Main config file of the application. */ angular - .module('opnfvApp').config(function () { + .module('opnfvApp').config(['$httpProvider', '$qProvider', function($httpProvider, $qProvider) { - } + $httpProvider.defaults.useXDomain = true; + delete $httpProvider.defaults.headers.common['X-Requested-With']; - ) + $qProvider.errorOnUnhandledRejections(false); + + } + + ]);
\ No newline at end of file diff --git a/utils/test/reporting/pages/app/scripts/config.router.js b/utils/test/reporting/pages/app/scripts/config.router.js index 641ea6a74..d38ad7507 100644 --- a/utils/test/reporting/pages/app/scripts/config.router.js +++ b/utils/test/reporting/pages/app/scripts/config.router.js @@ -23,7 +23,7 @@ angular.module('opnfvApp') $stateProvider .state('landingpage', { url: "/landingpage", - //controller: 'MainCtrl', + controller: 'MainController', templateUrl: "views/main.html", data: { pageTitle: '首页', specialClass: 'landing-page' }, resolve: { diff --git a/utils/test/reporting/pages/app/scripts/controllers/main.controller.js b/utils/test/reporting/pages/app/scripts/controllers/main.controller.js new file mode 100644 index 000000000..2054dc2dd --- /dev/null +++ b/utils/test/reporting/pages/app/scripts/controllers/main.controller.js @@ -0,0 +1,32 @@ +'use strict'; + +/** + * @ngdoc function + * @name opnfvdashBoardAngularApp.controller:MainPageController + * @description + * # TableController + * Controller of the opnfvdashBoardAngularApp + */ +angular.module('opnfvApp') + .controller('MainController', ['$scope', '$state', '$stateParams', function($scope, $state, $stateParams) { + + init(); + + function init() { + $scope.goTest = goTest; + $scope.goLogin = goLogin; + + } + + function goTest() { + $state.go("select.selectTestCase"); + } + + function goLogin() { + $state.go("login"); + } + + + + + }]);
\ No newline at end of file diff --git a/utils/test/reporting/pages/app/scripts/controllers/table.controller.js b/utils/test/reporting/pages/app/scripts/controllers/table.controller.js index 8ca1e474c..0f3a17a03 100644 --- a/utils/test/reporting/pages/app/scripts/controllers/table.controller.js +++ b/utils/test/reporting/pages/app/scripts/controllers/table.controller.js @@ -8,255 +8,131 @@ * Controller of the opnfvdashBoardAngularApp */ angular.module('opnfvApp') - .controller('TableController', ['$scope', '$state', '$stateParams', 'TableFactory', function ($scope, $state, $stateParams, TableFactory) { + .controller('TableController', ['$scope', '$state', '$stateParams', '$http', 'TableFactory', function($scope, $state, $stateParams, $http, TableFactory) { $scope.filterlist = []; $scope.selection = []; - $scope.statusList = ["Success", "Warning", "Danger"]; - $scope.projectList = ["Deployment", "Functest", "Yardstick"]; - $scope.installerList = ["apex", "compass", "fuel", "joid"]; - $scope.versionlist = ["Colorado", "Master"]; - $scope.loopci = ["Daily", "Weekly", "Monthly"]; - $scope.time = ["10 days", "1 Month"]; + $scope.statusList = []; + $scope.projectList = []; + $scope.installerList = []; + $scope.versionlist = []; + $scope.loopci = []; + $scope.time = []; $scope.tableDataAll = {}; $scope.tableInfoAll = {}; + $scope.scenario = {}; + $scope.VersionConfig = { + create: true, + valueField: 'title', + labelField: 'title', + delimiter: '|', + maxItems: 1, + placeholder: 'Version', + onChange: function(value) { + checkElementArrayValue($scope.selection, $scope.VersionOption); + $scope.selection.push(value); + // console.log($scope.selection); + getScenarioData(); + } + } - $scope.scenario = - { - "scenarios": { - "os-nosdn-kvm-noha": { - "status": "Success", - "installers": { - "apex": [ - { - "project": "Deployment", - "score": "13/14", - "status": "SUCCESS", - - - }, - { - "project": "Functest", - "score": "null", - "status": "SUCCESS" - }, - { - "project": "Yardstick", - "score": "13/14", - "status": "SUCCESS" - } - ], - "compass": [ - { - "project": "Deployment", - "score": "13/14", - "status": "SUCCESS" - }, - { - "project": "Functest", - "score": "13/14", - "status": "SUCCESS" - }, - { - "project": "Yardstick", - "score": "13/14", - "status": "SUCCESS" - } - ], - "fuel": [ - { - "project": "Deployment", - "score": "13/14", - "status": "SUCCESS" - }, - { - "project": "Functest", - "score": "13/14", - "status": "SUCCESS" - }, - { - "project": "Yardstick", - "score": "13/14", - "status": "SUCCESS" - } - ], - "joid": [ - { - "project": "Deployment", - "score": "13/14", - "status": "SUCCESS" - }, - { - "project": "Functest", - "score": "13/14", - "status": "SUCCESS" - }, - { - "project": "Yardstick", - "score": "13/14", - "status": "SUCCESS" - } - ] - } - }, - "os-nosdn-ovs-ha": { - "status": "Danger", - "installers": { - "apex": [ - { - "project": "Deployment", - "score": "13/14", - "status": "SUCCESS", - - - }, - { - "project": "Functest", - "score": "13/14", - "status": "SUCCESS" - }, - { - "project": "Yardstick", - "score": "13/14", - "status": "SUCCESS" - } - ], - "compass": [ - { - "project": "Deployment", - "score": "13/14", - "status": "SUCCESS" - }, - { - "project": "Functest", - "score": "13/14", - "status": "SUCCESS" - }, - { - "project": "Yardstick", - "score": "13/14", - "status": "SUCCESS" - } - ], - "fuel": [ - { - "project": "Deployment", - "score": "13/14", - "status": "SUCCESS" - }, - { - "project": "Functest", - "score": "13/14", - "status": "SUCCESS" - }, - { - "project": "Yardstick", - "score": "13/14", - "status": "SUCCESS" - } - ], - "joid": [ - { - "project": "Deployment", - "score": "13/14", - "status": "SUCCESS" - }, - { - "project": "Functest", - "score": "13/14", - "status": "SUCCESS" - }, - { - "project": "Yardstick", - "score": "13/14", - "status": "SUCCESS" - } - ] - } - }, - "os-nosdn-ovs-noha": { - "status": "Warning", - "installers": { - "apex": [ - { - "project": "Deployment", - "score": "13/14", - "status": "SUCCESS", - - - }, - { - "project": "Functest", - "score": "13/14", - "status": "SUCCESS" - }, - { - "project": "Yardstick", - "score": "13/14", - "status": "SUCCESS" - } - ], - "compass": [ - { - "project": "Deployment", - "score": "13/14", - "status": "SUCCESS" - }, - { - "project": "Functest", - "score": "13/14", - "status": "SUCCESS" - }, - { - "project": "Yardstick", - "score": "13/14", - "status": "SUCCESS" - } - ], - "fuel": [ - { - "project": "Deployment", - "score": "13/14", - "status": "SUCCESS" - }, - { - "project": "Functest", - "score": "13/14", - "status": "SUCCESS" - }, - { - "project": "Yardstick", - "score": "13/14", - "status": "SUCCESS" - } - ], - "joid": [ - { - "project": "Deployment", - "score": "13/14", - "status": "SUCCESS" - }, - { - "project": "Functest", - "score": "13/14", - "status": "SUCCESS" - }, - { - "project": "Yardstick", - "score": "13/14", - "status": "SUCCESS" - } - ] - } - } + $scope.LoopConfig = { + create: true, + valueField: 'title', + labelField: 'title', + delimiter: '|', + maxItems: 1, + placeholder: 'Loop', + onChange: function(value) { + checkElementArrayValue($scope.selection, $scope.LoopOption); + $scope.selection.push(value); + // console.log($scope.selection); + getScenarioData(); + + } + } + + $scope.TimeConfig = { + create: true, + valueField: 'title', + labelField: 'title', + delimiter: '|', + maxItems: 1, + placeholder: 'Time', + onChange: function(value) { + checkElementArrayValue($scope.selection, $scope.TimeOption); + $scope.selection.push(value); + // console.log($scope.selection) + getScenarioData(); + + + } + } + + + init(); + + function init() { + $scope.toggleSelection = toggleSelection; + getScenarioData(); + // radioSetting(); + getFilters(); + } + + function getFilters() { + TableFactory.getFilter().get({ + + + }).$promise.then(function(response) { + if (response != null) { + $scope.statusList = response.filters.status; + $scope.projectList = response.filters.projects; + $scope.installerList = response.filters.installers; + $scope.versionlist = response.filters.version; + $scope.loopci = response.filters.loops; + $scope.time = response.filters.time; + + $scope.statusListString = $scope.statusList.toString(); + $scope.projectListString = $scope.projectList.toString(); + $scope.installerListString = $scope.installerList.toString(); + $scope.VersionSelected = $scope.versionlist[1]; + $scope.LoopCiSelected = $scope.loopci[0]; + $scope.TimeSelected = $scope.time[0]; + radioSetting($scope.versionlist, $scope.loopci, $scope.time); + + } else { + alert("网络错误"); } + }) + } + + function getScenarioData() { + + var utl = BASE_URL + '/scenarios'; + var data = { + 'status': ['success', 'danger', 'warning'], + 'projects': ['functest', 'yardstick'], + 'installers': ['apex', 'compass', 'fuel', 'joid'], + 'version': $scope.VersionSelected, + 'loops': $scope.LoopCiSelected, + 'time': $scope.TimeSelected }; + var config = { + headers: { + 'Content-Type': 'application/x-www-form-urlencoded;charset=utf-8;' + } + } + $http.post(utl, data, config).then(function(response) { + if (response.status == 200) { + $scope.scenario = response.data; + constructJson(); + } + }) + } - // var headData = Object.keys($scope.scenario.scenarios.os_nosdn_kvm_noha.installers); - // $scope.headData = headData; - //construct json + //construct json function constructJson() { var colspan; @@ -267,19 +143,22 @@ angular.module('opnfvApp') for (var item in $scope.scenario.scenarios) { - - - - var headData = Object.keys($scope.scenario.scenarios[item].installers); + var headData = Object.keys($scope.scenario.scenarios[item].installers).sort(); var scenarioStatus = $scope.scenario.scenarios[item].status; - + var scenarioStatusDisplay; + if (scenarioStatus == "success") { + scenarioStatusDisplay = "navy"; + } else if (scenarioStatus == "danger") { + scenarioStatusDisplay = "danger"; + } else if (scenarioStatus == "warning") { + scenarioStatusDisplay = "warning"; + } InstallerData = headData; var projectData = []; var datadisplay = []; var projects = []; - for (var j = 0; j < headData.length; j++) { projectData.push($scope.scenario.scenarios[item].installers[headData[j]]); @@ -289,9 +168,30 @@ angular.module('opnfvApp') for (var k = 0; k < projectData[j].length; k++) { projects.push(projectData[j][k].project); var temArray = []; - temArray.push(projectData[j][k].score); - temArray.push(projectData[j][k].project); - temArray.push(headData[j]); + if (projectData[j][k].score == null) { + temArray.push("null"); + temArray.push(projectData[j][k].project); + temArray.push(headData[j]); + } else { + temArray.push(projectData[j][k].score); + temArray.push(projectData[j][k].project); + temArray.push(headData[j]); + } + + + if (projectData[j][k].status == "platinium") { + temArray.push("primary"); + temArray.push("P"); + } else if (projectData[j][k].status == "gold") { + temArray.push("danger"); + temArray.push("G"); + } else if (projectData[j][k].status == "silver") { + temArray.push("warning"); + temArray.push("S"); + } else if (projectData[j][k].status == null) { + temArray.push("null"); + } + datadisplay.push(temArray); } @@ -301,13 +201,21 @@ angular.module('opnfvApp') colspan = projects.length / headData.length; var tabledata = { - scenarioName: item, Installer: InstallerData, projectData: projectData, projects: projects, - datadisplay: datadisplay, colspan: colspan, status: scenarioStatus + scenarioName: item, + Installer: InstallerData, + projectData: projectData, + projects: projects, + datadisplay: datadisplay, + colspan: colspan, + status: scenarioStatus, + statusDisplay: scenarioStatusDisplay }; JSON.stringify(tabledata); $scope.tableDataAll.scenario.push(tabledata); + // console.log(tabledata); + } @@ -315,15 +223,13 @@ angular.module('opnfvApp') var tempHeadData = []; - - for (var i = 0; i < InstallerData.length; i++) { for (var j = 0; j < colspan; j++) { tempHeadData.push(InstallerData[i]); } } - console.log(tempHeadData); + //console.log(tempHeadData); var projectsInfoAll = []; @@ -334,13 +240,14 @@ angular.module('opnfvApp') projectsInfoAll.push(tempA); } - console.log(projectsInfoAll); + //console.log(projectsInfoAll); $scope.tableDataAll["colspan"] = colspan; $scope.tableDataAll["Installer"] = InstallerData; $scope.tableDataAll["Projects"] = projectsInfoAll; - console.log($scope.tableDataAll); + // console.log($scope.tableDataAll); + $scope.colspan = $scope.tableDataAll.colspan; } @@ -353,58 +260,11 @@ angular.module('opnfvApp') return size; } - init(); - function init() { - $scope.toggleSelection = toggleSelection; - - constructJson(); - - } - - // $scope.test=false; + $scope.colspan = $scope.tableDataAll.colspan; + // console.log($scope.colspan); - var statusListString = $scope.statusList.toString(); - var projectListString = $scope.projectList.toString(); - var installerListString = $scope.installerList.toString(); - - $scope.colspan=$scope.tableDataAll.colspan; - //filter function - function filterData() { - - - $scope.selectInstallers = []; - $scope.selectProjects = []; - $scope.selectStatus = []; - for (var i = 0; i < $scope.selection.length; i++) { - if (statusListString.indexOf($scope.selection[i]) > -1) { - $scope.selectStatus.push($scope.selection[i]); - } - if (projectListString.indexOf($scope.selection[i]) > -1) { - $scope.selectProjects.push($scope.selection[i]); - } - if (installerListString.indexOf($scope.selection[i]) > -1) { - $scope.selectInstallers.push($scope.selection[i]); - } - } - - $scope.colspan=$scope.selectProjects.length; - //when some selection is empty, we set it full - if($scope.selectInstallers.length==0){ - $scope.selectInstallers=$scope.installerList; - - } - if($scope.selectProjects.length==0){ - $scope.selectProjects=$scope.projectList; - $scope.colspan=$scope.tableDataAll.colspan; - } - if($scope.selectStatus.length==0){ - $scope.selectStatus=$scope.statusList - } - } - - - //find all same element index + //find all same element index function getSameElementIndex(array, element) { var indices = []; var idx = array.indexOf(element); @@ -424,64 +284,31 @@ angular.module('opnfvApp') } - - $scope.VersionOption = [ - { title: 'Colorado' }, - { title: 'Master' } - ]; - $scope.VersionConfig = { - create: true, - valueField: 'title', - labelField: 'title', - delimiter: '|', - maxItems: 1, - placeholder: 'Version', - onChange: function (value) { - checkElementArrayValue($scope.selection, $scope.VersionOption); - $scope.selection.push(value); - // console.log($scope.selection); - + function radioSetting(array1, array2, array3) { + var tempVersion = []; + var tempLoop = []; + var tempTime = []; + for (var i = 0; i < array1.length; i++) { + var temp = { + title: array1[i] + }; + tempVersion.push(temp); } - - } - - $scope.LoopOption = [ - { title: 'Daily' }, - { title: 'Weekly' }, - { title: 'Monthly' } - ]; - $scope.LoopConfig = { - create: true, - valueField: 'title', - labelField: 'title', - delimiter: '|', - maxItems: 1, - placeholder: 'Loop', - onChange: function (value) { - checkElementArrayValue($scope.selection, $scope.LoopOption); - $scope.selection.push(value); - // console.log($scope.selection); - + for (var i = 0; i < array2.length; i++) { + var temp = { + title: array2[i] + }; + tempLoop.push(temp); } - } - - $scope.TimeOption = [ - { title: '10 days' }, - { title: '1 month' } - ]; - $scope.TimeConfig = { - create: true, - valueField: 'title', - labelField: 'title', - delimiter: '|', - maxItems: 1, - placeholder: 'Time', - onChange: function (value) { - checkElementArrayValue($scope.selection, $scope.TimeOption); - $scope.selection.push(value); - // console.log($scope.selection) - + for (var i = 0; i < array3.length; i++) { + var temp = { + title: array3[i] + }; + tempTime.push(temp); } + $scope.VersionOption = tempVersion; + $scope.LoopOption = tempLoop; + $scope.TimeOption = tempTime; } //remove element in the array @@ -508,13 +335,51 @@ angular.module('opnfvApp') if (idx > -1) { $scope.selection.splice(idx, 1); - } - else { + filterData($scope.selection) + } else { $scope.selection.push(status); + filterData($scope.selection) } - console.log($scope.selection); - filterData(); + // console.log($scope.selection); } - }]); + //filter function + function filterData(selection) { + + $scope.selectInstallers = []; + $scope.selectProjects = []; + $scope.selectStatus = []; + for (var i = 0; i < selection.length; i++) { + if ($scope.statusListString.indexOf(selection[i]) > -1) { + $scope.selectStatus.push(selection[i]); + } + if ($scope.projectListString.indexOf(selection[i]) > -1) { + $scope.selectProjects.push(selection[i]); + } + if ($scope.installerListString.indexOf(selection[i]) > -1) { + $scope.selectInstallers.push(selection[i]); + } + } + + $scope.colspan = $scope.selectProjects.length; + //when some selection is empty, we set it full + if ($scope.selectInstallers.length == 0) { + $scope.selectInstallers = $scope.installerList; + + } + if ($scope.selectProjects.length == 0) { + $scope.selectProjects = $scope.projectList; + $scope.colspan = $scope.tableDataAll.colspan; + } + if ($scope.selectStatus.length == 0) { + $scope.selectStatus = $scope.statusList + } + + // console.log($scope.selectStatus); + // console.log($scope.selectProjects); + + } + + + }]);
\ No newline at end of file diff --git a/utils/test/reporting/pages/app/scripts/data.json b/utils/test/reporting/pages/app/scripts/data.json deleted file mode 100644 index a15fdf37e..000000000 --- a/utils/test/reporting/pages/app/scripts/data.json +++ /dev/null @@ -1,76 +0,0 @@ - -{"scenarios": { - "os-nosdn-kvm-noha": { - "status": "Success", - "installers": { - "apex": [ - { - "project": "Deployment", - "score": "13/14", - "status": "SUCCESS" - }, - { - "project": "Functest", - "score": "13/14", - "status": "SUCCESS" - }, - { - "project": "Yardstick", - "socre": "13/14", - "status": "SUCCESS" - } - ], - "compass": [ - { - "project": "Deployment", - "score": "13/14", - "status": "SUCCESS" - }, - { - "project": "Functest", - "score": "13/14", - "status": "SUCCESS" - }, - { - "project": "Yardstick", - "socre": "13/14", - "status": "SUCCESS" - } - ], - "fuel": [ - { - "project": "Deployment", - "score": "13/14", - "status": "SUCCESS" - }, - { - "project": "Functest", - "score": "13/14", - "status": "SUCCESS" - }, - { - "project": "Yardstick", - "socre": "13/14", - "status": "SUCCESS" - } - ], - "joid": [ - { - "project": "Deployment", - "score": "13/14", - "status": "SUCCESS" - }, - { - "project": "Functest", - "score": "13/14", - "status": "SUCCESS" - }, - { - "project": "Yardstick", - "socre": "13/14", - "status": "SUCCESS" - } - ] - } - } -}} diff --git a/utils/test/reporting/pages/app/scripts/factory/table.factory.js b/utils/test/reporting/pages/app/scripts/factory/table.factory.js index 22443221e..a2e2aeff0 100644 --- a/utils/test/reporting/pages/app/scripts/factory/table.factory.js +++ b/utils/test/reporting/pages/app/scripts/factory/table.factory.js @@ -4,17 +4,23 @@ * get data factory */ angular.module('opnfvApp') - .factory('TableFactory', function ($resource, $rootScope) { - // var baseUrl = base_Url; + .factory('TableFactory', function($resource, $rootScope) { return { - getFilter: function () { - return $resource(baseUrl + '/', {}, { - 'post': { - method: 'POST', + getFilter: function() { + return $resource(BASE_URL + '/filters', {}, { + 'get': { + method: 'GET', } }); + }, + getScenario: function() { + return $resource(BASE_URL + '/scenarios', {}, { + 'post': { + method: 'POST', + } + }) } }; - }); + });
\ No newline at end of file diff --git a/utils/test/reporting/pages/app/styles/custome.css b/utils/test/reporting/pages/app/styles/custome.css index dadc68a03..b498cf04d 100644 --- a/utils/test/reporting/pages/app/styles/custome.css +++ b/utils/test/reporting/pages/app/styles/custome.css @@ -1,8 +1,8 @@ .container-tablesize { - margin: auto 5%; + margin: auto 5%; } -.btn-outline { +.btn-outline { border-color: white; } @@ -29,6 +29,68 @@ } .myhr { - border:0.5px dashed #e7eaec; - border-top:1px;margin-bottom: 3px; -}
\ No newline at end of file + border: 0.5px dashed #e7eaec; + border-top: 1px; + margin-bottom: 3px; +} + +td.null { + background-color: #e7eaec; + color: #e7eaec; +} + +input[type="radio"][disabled], +input[type="checkbox"][disabled], +input[type="radio"].disabled, +input[type="checkbox"].disabled, +fieldset[disabled] input[type="radio"], +fieldset[disabled] input[type="checkbox"] { + cursor: not-allowed; + display: none; +} + +body, +html { + margin: 0; + padding: 0; + min-height: 100%; +} + + +/*img[usemap] { + border: none; + height: auto; + max-width: 100%; + width: auto; +}*/ + +.popup { + position: absolute; + display: none; + /*background-color: #dd8;*/ + border-radius: 5px 5px 5px 5px; + background-color: #f3f3f4; + opacity: 0.9; +} + + +/* +body { + height: 1200px; +} + +html { + min-height: 100%; +}*/ + + +/*html, +body { + height: 100%; +} + +#page-wrapper { + position: inherit; + margin: 0 0 0 220px; + min-height: 773px; +}*/
\ No newline at end of file diff --git a/utils/test/reporting/pages/app/styles/fonts/glyphicons-halflings-regular.svg b/utils/test/reporting/pages/app/styles/fonts/glyphicons-halflings-regular.svg index 187805af6..94fb5490a 100644 --- a/utils/test/reporting/pages/app/styles/fonts/glyphicons-halflings-regular.svg +++ b/utils/test/reporting/pages/app/styles/fonts/glyphicons-halflings-regular.svg @@ -285,4 +285,4 @@ <glyph unicode="🔑" d="M250 1200h600q21 0 35.5 -14.5t14.5 -35.5v-400q0 -21 -14.5 -35.5t-35.5 -14.5h-150v-500l-255 -178q-19 -9 -32 -1t-13 29v650h-150q-21 0 -35.5 14.5t-14.5 35.5v400q0 21 14.5 35.5t35.5 14.5zM400 1100v-100h300v100h-300z" /> <glyph unicode="🚪" d="M250 1200h750q39 0 69.5 -40.5t30.5 -84.5v-933l-700 -117v950l600 125h-700v-1000h-100v1025q0 23 15.5 49t34.5 26zM500 525v-100l100 20v100z" /> </font> -</defs></svg> +</defs></svg>
\ No newline at end of file diff --git a/utils/test/reporting/pages/app/views/commons/table.html b/utils/test/reporting/pages/app/views/commons/table.html index ed9300edd..f504bd76b 100644 --- a/utils/test/reporting/pages/app/views/commons/table.html +++ b/utils/test/reporting/pages/app/views/commons/table.html @@ -29,81 +29,85 @@ <div class=" col-md-12" data-toggle="buttons" aria-pressed="false"> <label> Status </label> - <label class="btn btn-outline btn-success btn-sm" style="height:25px; margin-right: 5px;" ng-repeat="status in statusList" - value={{status}} ng-checked="selection.indexOf(status)>-1" ng-click="toggleSelection(status)"> + <label class="btn btn-outline btn-success btn-sm" style="height:25px; margin-right: 5px;" ng-repeat="status in statusList" value={{status}} ng-checked="selection.indexOf(status)>-1" ng-click="toggleSelection(status)"> <input type="checkbox" disabled="disabled" > {{status}} + </label> </div> - <hr class="myhr"> + <hr class="myhr"> <div class=" col-md-12" data-toggle="buttons"> - <label> Projects </label> - <label class="btn btn-outline btn-success btn-sm " style="height:25px;margin-right: 5px;" ng-repeat="project in projectList" - value={{project}} ng-checked="selection.indexOf(project)>-1" ng-click="toggleSelection(project)"> + <label> Projects </label> + <label class="btn btn-outline btn-success btn-sm " style="height:25px;margin-right: 5px;" ng-repeat="project in projectList" value={{project}} ng-checked="selection.indexOf(project)>-1" ng-click="toggleSelection(project)"> <input type="checkbox" disabled="disabled"> {{project}} </label> </div> - <hr class="myhr"> + <hr class="myhr"> <div class=" col-md-12" data-toggle="buttons"> <label> Installers </label> - <label class="btn btn-outline btn-success btn-sm" style="height:25px;margin-right: 5px;" ng-repeat="installer in installerList" - value={{installer}} ng-checked="selection.indexOf(installer)" ng-click="toggleSelection(installer)"> + <label class="btn btn-outline btn-success btn-sm" style="height:25px;margin-right: 5px;" ng-repeat="installer in installerList" value={{installer}} ng-checked="selection.indexOf(installer)>-1" ng-click="toggleSelection(installer)"> <input type="checkbox" disabled="disabled"> {{installer}} </label> - </div> + </div> - <hr style="border:0.5px dashed #e7eaec;border-top:1px;margin-bottom:10px;"> + <hr style="border:0.5px dashed #e7eaec;border-top:1px;margin-bottom:10px;"> - <div class=" col-md-1" style="margin-top:5px;margin-right: 5px;"> - <selectize options="VersionOption" ng-model="VersionSelected" config="VersionConfig"></selectize> + <div class=" col-md-1" style="margin-top:5px;margin-right: 5px;"> + <selectize options="VersionOption" ng-model="VersionSelected" config="VersionConfig"></selectize> - </div> + </div> - <div class=" col-md-1" style="margin-top:5px;margin-left: 5px;margin-right: 5px;"> - <selectize options="LoopOption" ng-model="LoopCiSelected" config="LoopConfig"></selectize> + <div class=" col-md-1" style="margin-top:5px;margin-right: 5px;"> + <selectize options="LoopOption" ng-model="LoopCiSelected" config="LoopConfig"></selectize> - </div> + </div> - <div class=" col-md-1" style="margin-top:5px;margin-left: 5px;margin-right: 5px;"> - <selectize options="TimeOption" ng-model="TimeSelected" config="TimeConfig"></selectize> + <div class=" col-md-1" style="margin-top:5px;margin-right: 5px;"> + <selectize options="TimeOption" ng-model="TimeSelected" config="TimeConfig"></selectize> + </div> </div> + <div class="table-responsive"> + + <table class="table table-bordered" id="table" ng-model="tableDataAll"> + <thead class="thead"> + <tr> + <th>Scenario </th> + <th colspan={{colspan}} ng-show="selectInstallers.indexOf(key)!=-1" value={{key}} ng-repeat="key in tableDataAll.Installer"><a href="notfound.html">{{key}}</a> </th> + </tr> + <tr> -</div> + <td></td> + <td ng-show="selectProjects.indexOf(project[0])!=-1 && selectInstallers.indexOf(project[1])!=-1" ng-repeat="project in tableDataAll.Projects track by $index" data={{project[1]}} value={{project[0]}}>{{project[0]}}</td> -<table class="table table-bordered" id="table" ng-model="tableDataAll"> - <thead class="thead"> - <tr > - <th>Scenario </th> - <th colspan={{colspan}} ng-show="selectInstallers.indexOf(key)!=-1" value={{key}} ng-repeat="key in tableDataAll.Installer"><a href="notfound.html">{{key}}</a> </th> - </tr> + </tr> + </thead> + <tbody class="tbody"> + <tr ng-repeat="scenario in tableDataAll.scenario" ng-show="selectStatus.indexOf(scenario.status)!=-1"> - <tr> + <td nowrap="nowrap" data={{scenario.status}}><span class="fa fa-circle text-{{scenario.statusDisplay}}"></span> <a href="notfound.html">{{scenario.scenarioName}}</a> </td> - <td align="justify"></td> - <td align="justify" ng-show="selectProjects.indexOf(project[0])!=-1 && selectInstallers.indexOf(project[1])!=-1" ng-repeat="project in tableDataAll.Projects track by $index" data={{project[1]}} value={{project[0]}}>{{project[0]}}</td> - </tr> - </thead> - <tbody class="tbody"> - <tr ng-repeat="scenario in tableDataAll.scenario" ng-show="selectStatus.indexOf(scenario.status)!=-1" > + <!--<td style="background-color:#e7eaec" align="justify" ng-if="data[0]=='Not Support'" ng-repeat="data in scenario.datadisplay track by $index" data={{data[1]}} value={{data[2]}}></td>--> - <td align="justify" data={{scenario.status}}><span class="fa fa-circle text-warning"><a href="notfound.html">{{scenario.scenarioName}}</a></span> </td> - <td align="justify" ng-show="selectInstallers.indexOf(data[2])!=-1 && selectProjects.indexOf(data[1])!=-1" ng-repeat="data in scenario.datadisplay track by $index" data={{data[1]}} value={{data[2]}} ><span class="label label-danger">D<a href="notfound.html"></a></span> {{data[0]}}</td> - </tr> - </tbody> -</table> + <td nowrap="nowrap" ng-show="selectInstallers.indexOf(data[2])!=-1 && selectProjects.indexOf(data[1])!=-1" ng-repeat="data in scenario.datadisplay track by $index" data={{data[1]}} value={{data[2]}} class={{data[0]}}> + <span class="label label-{{data[3]}}">{{data[4]}}</a></span> {{data[0]}}</td> - <div class="pull-right"> - <span class="label label-danger">D</span>danger<span style="padding-left:20px"></span> - <span class="label label-primary">S</span><span>success</span><span style="padding-left:20px"></span> - <span class="label label-warning">W</span><span>warning</span> + </tr> + </tbody> + </table> + </div> + + <div class="pull-right" style="margin-top: 5px"> + <span class="label label-danger">G</span>gold<span style="padding-left:20px"></span> + <span class="label label-primary">P</span><span>platinium</span><span style="padding-left:20px"></span> + <span class="label label-warning">S</span><span>silver</span> </div> + </div> </div> </div> -</div> -</section> +</section>
\ No newline at end of file diff --git a/utils/test/reporting/pages/app/views/main.html b/utils/test/reporting/pages/app/views/main.html index 1e3fe9e5a..cca893713 100644 --- a/utils/test/reporting/pages/app/views/main.html +++ b/utils/test/reporting/pages/app/views/main.html @@ -1,186 +1,171 @@ - <div class="navbar-wrapper"> - <nav class="navbar navbar-default navbar-fixed-top" role="navigation"> - <div class="container"> - <div class="navbar-header page-scroll"> - <button type="button" class="navbar-toggle collapsed" data-toggle="collapse" data-target="#navbar" aria-expanded="false" - aria-controls="navbar"> + <nav class="navbar navbar-default navbar-fixed-top" role="navigation"> + <div class="container"> + <div class="navbar-header page-scroll"> + <button type="button" class="navbar-toggle collapsed" data-toggle="collapse" data-target="#navbar" aria-expanded="false" aria-controls="navbar"> <span class="sr-only">Toggle navigation</span> <span class="icon-bar"></span> <span class="icon-bar"></span> <span class="icon-bar"></span> </button> - <a class="navbar-brand" href="index.html">OPNFV-DASHBOARD</a> - </div> - <div id="navbar" class="navbar-collapse collapse"> - <ul class="nav navbar-nav navbar-right"> - <li><a href="#page-top">Home</a></li> - <li><a href="#DashBoard">DashBoard</a></li> - <!--<li><a href="#team">Team</a></li> + <a class="navbar-brand" href="index.html">OPNFV-DASHBOARD</a> + </div> + <div class="navbar-collapse collapse"> + <ul class="nav navbar-nav navbar-right"> + <li><a href="#page-top">Home</a></li> + <li><a href="#DashBoard">DashBoard</a></li> + <li><a ui-sref="select.selectTestCase">TestCase</a></li> + <li><a ui-sref="login">Login</a></li> + <!--<li><a href="#team">Team</a></li> <li><a href="#testimonials">Testimonials</a></li> <li><a href="#pricing">Pricing</a></li> <li><a href="#contact">Contact</a></li>--> - </ul> - </div> - </div> - </nav> + </ul> + </div> + </div> + </nav> </div> <div id="inSlider" class="carousel carousel-fade" data-ride="carousel"> - <ol class="carousel-indicators"> - <!--<li data-target="#inSlider" data-slide-to="0" class="active"></li> + <ol class="carousel-indicators"> + <!--<li data-target="#inSlider" data-slide-to="0" class="active"></li> <li data-target="#inSlider" data-slide-to="1"></li>--> - </ol> - <div class="carousel-inner" role="listbox"> - <div class="item active"> - <div class="container"> - <div class="carousel-caption"> - <h1>OPNFV<br/> facilitates the development and evolution<br/> of NFV components across<br/> various open source ecosystems<br/> - </h1> - <!--<p>Lorem Ipsum is simply dummy text of the printing.</p> + </ol> + <div class="carousel-inner" role="listbox"> + <div class="item active"> + <div class="container"> + <div class="carousel-caption"> + <h1>OPNFV<br/> facilitates the development and evolution<br/> of NFV components across<br/> various open source ecosystems<br/> + </h1> + <!--<p>Lorem Ipsum is simply dummy text of the printing.</p> <p>--> - <a class="btn btn-lg btn-primary" href="#" role="button">READ MORE</a> - <!--<a class="caption-link" href="#" role="button">Inspinia Theme</a>--> - <!--</p>--> + <a class="btn btn-lg btn-primary" href="#" role="button">READ MORE</a> + <!--<a class="caption-link" href="#" role="button">Inspinia Theme</a>--> + <!--</p>--> + </div> + + </div> + <!-- Set background for slide in css --> + <div class="header-back one" style="background: url('images/header_one.jpg') 50% 0 no-repeat;"></div> + </div> - <!--<div class="carousel-image wow zoomIn"> - <img src="img/landing/laptop.png" alt="laptop"/> - </div>--> - </div> - <!-- Set background for slide in css --> - <div class="header-back one" style="background: url('images/header_one.jpg') 50% 0 no-repeat;"></div> </div> - <!--<div class="item"> - <div class="container"> - <div class="carousel-caption blank"> - <h1>We create meaningful <br/> interfaces that inspire.</h1> - <p>Cras justo odio, dapibus ac facilisis in, egestas eget quam.</p> - <p><a class="btn btn-lg btn-primary" href="#" role="button">Learn more</a></p> - </div> - </div>--> - <!-- Set background for slide in css --> - <!--<div class="header-back two"></div> - </div>--> - </div> - <!--<a class="left carousel-control" href="#inSlider" role="button" data-slide="prev"> - <span class="glyphicon glyphicon-chevron-left" aria-hidden="true"></span> - <span class="sr-only">Previous</span> - </a> - <a class="right carousel-control" href="#inSlider" role="button" data-slide="next"> - <span class="glyphicon glyphicon-chevron-right" aria-hidden="true"></span> - <span class="sr-only">Next</span> - </a>--> + </div> - <section id="DashBoard" class="container services"> - <div class="row"> +<section id="DashBoard" class="container services"> + <div class="row"> - <h1> - OPNFV’s goals are to: - </h1> - <div class="col-sm-3"> + <h1> + OPNFV’s goals are to: + </h1> + <div class="col-sm-3"> - <p>Develop an integrated and tested open source platform that can be used to build NFV functionality--accelerating - the introduction of new products and services</p> - <p><a class="navy-link" href="#" role="button">Details »</a></p> - </div> - <div class="col-sm-3"> + <p>Develop an integrated and tested open source platform that can be used to build NFV functionality--accelerating the introduction of new products and services</p> + <p><a class="navy-link" href="#" role="button">Details »</a></p> + </div> + <div class="col-sm-3"> - <p>Include participation of leading end users to validate that OPNFV meets the needs of user community</p> - <p><a class="navy-link" href="#" role="button">Details »</a></p> - </div> - <div class="col-sm-3"> + <p>Include participation of leading end users to validate that OPNFV meets the needs of user community</p> + <p><a class="navy-link" href="#" role="button">Details »</a></p> + </div> + <div class="col-sm-3"> - <p>Contribute to and participate in relevant open source projects that will be leveraged in the OPNFV platform; - ensuring consistency, performance and interoperability among open source components</p> - <p><a class="navy-link" href="#" role="button">Details »</a></p> - </div> - <div class="col-sm-3"> + <p>Contribute to and participate in relevant open source projects that will be leveraged in the OPNFV platform; ensuring consistency, performance and interoperability among open source components</p> + <p><a class="navy-link" href="#" role="button">Details »</a></p> + </div> + <div class="col-sm-3"> - <p>Establish an ecosystem for NFV solutions based on open standards and software to meet the needs of end users</p> - <p><a class="navy-link" href="#" role="button">Details »</a></p> - </div> - <div class="col-sm-3"> + <p>Establish an ecosystem for NFV solutions based on open standards and software to meet the needs of end users</p> + <p><a class="navy-link" href="#" role="button">Details »</a></p> + </div> + <div class="col-sm-3"> - <p>Promote OPNFV as the preferred platform and community for open source NFV</p> - <p><a class="navy-link" href="#" role="button">Details »</a></p> - </div> + <p>Promote OPNFV as the preferred platform and community for open source NFV</p> + <p><a class="navy-link" href="#" role="button">Details »</a></p> </div> - </section> + </div> +</section> <div ui-view></div> <section id="contact" class="gray-section contact" style="background-image: url(images/word_map.png)"> - <div class="container"> - <div class="row m-b-lg"> - <div class="col-lg-12 text-center"> - <div class="navy-line"></div> - <h1>Contact Us</h1> - </div> - </div> - <div class="row m-b-lg"> - <div class="col-lg-3 col-lg-offset-3"> - <address> + <div class="container"> + <div class="row m-b-lg"> + <div class="col-lg-12 text-center"> + <div class="navy-line"></div> + <h1>Contact Us</h1> + </div> + </div> + <div class="row m-b-lg"> + <div class="col-lg-3 col-lg-offset-3"> + <address> <strong><span class="navy">Press, Analyst, or Speaking Inquiries</span></strong><br/> pr@opnfv.org <br/> </address> - <address> + <address> <strong><span class="navy">OPNFV Events</span></strong><br/> events@opnfv.org <br/> </address> - <address> + <address> <strong><span class="navy">IT Support</span></strong><br/>opnfv-helpdesk@rt.linuxfoundation.org <br/> </address> - </div> + </div> - <div class="col-lg-4"> - <address> + <div class="col-lg-4"> + <address> <strong><span class="navy">To submit and track bugs related to OPNFV</span></strong><br/>Please visit https://jira.opnfv.org <br/> </address> - <address> + <address> <strong><span class="navy">Newsletter</span></strong><br/>Sign up for the OPNFV newsletter <br/> </address> - <address> + <address> <strong><span class="navy">Membership</span></strong><br/>Please visit the Join as a Member page <br/> </address> - </div> - </div> - <div class="row"> - <div class="col-lg-12 text-center"> - <img src="images/logo.png" /> + </div> + </div> + <div class="row"> + <div class="col-lg-12 text-center"> + <img src="images/logo.png" /> - </div> - </div> - <div class="row"> - <div class="col-lg-8 col-lg-offset-2 text-center m-t-lg m-b-lg"> - <p><strong>© 2016 Open Platform for NFV Project, Inc</strong><br/> A Linux Foundation Collaborative Project. All - Rights Reserved. Open Platform for NFV and OPNFV are trademarks of the Open Platform for NFV Project, Inc. Linux - Foundation is a registered trademark of The Linux Foundation. Linux is a registered trademark of Linus Torvalds. - Please see our terms of use, trademark policy, and privacy policy. - </p> - </div> + </div> + </div> + <div class="row"> + <div class="col-lg-8 col-lg-offset-2 text-center m-t-lg m-b-lg"> + <p><strong>© 2016 Open Platform for NFV Project, Inc</strong><br/> A Linux Foundation Collaborative Project. All Rights Reserved. Open Platform for NFV and OPNFV are trademarks of the Open Platform for NFV Project, Inc. Linux Foundation + is a registered trademark of The Linux Foundation. Linux is a registered trademark of Linus Torvalds. Please see our terms of use, trademark policy, and privacy policy. + </p> + </div> + </div> </div> - </div> </section> <script> + $(document).ready(function() { - $(document).ready(function () { + // $('body').scrollspy({ + // target: '.navbar-fixed-top', + // offset: 80 + // }); - $('body').scrollspy({ - target: '.navbar-fixed-top', - offset: 80 + //Page scrolling feature + $('a.page-scroll').bind('click', function(event) { + var link = $(this); + $('html, body').stop().animate({ + scrollTop: $(link.attr('href')).offset().top - 50 + }, 500); + event.preventDefault(); + $("#navbar").collapse('hide'); }); - // Page scrolling feature $('a.page-scroll').bind('click', function(event) { var link = $(this); $('html, body').stop().animate({ @@ -190,63 +175,56 @@ $("#navbar").collapse('hide'); }); - - console.log( $("selectVersion").val()); - }); - // $(".select2_demo_1").select2(); - // $(".select2_demo_2").select2(); - // $(".select2_demo_3").select2({ - // placeholder: "Version", - // allowClear: true - // }); - // $(".select2_demo_4").select2({ - // placeholder: "Period", - // allowClear: true - // }); - - var config = { - '.chosen-select' : {}, - '.chosen-select-deselect' : {allow_single_deselect:true}, - '.chosen-select-no-single' : {disable_search_threshold:10}, - '.chosen-select-no-results': {no_results_text:'Oops, nothing found!'}, - '.chosen-select-width' : {width:"95%"} - } - for (var selector in config) { - $(selector).chosen(config[selector]); - } + '.chosen-select': {}, + '.chosen-select-deselect': { + allow_single_deselect: true + }, + '.chosen-select-no-single': { + disable_search_threshold: 10 + }, + '.chosen-select-no-results': { + no_results_text: 'Oops, nothing found!' + }, + '.chosen-select-width': { + width: "95%" + } + } + for (var selector in config) { + $(selector).chosen(config[selector]); + } var cbpAnimatedHeader = (function() { var docElem = document.documentElement, - header = document.querySelector( '.navbar-default' ), - didScroll = false, - changeHeaderOn = 200; + header = document.querySelector('.navbar-default'), + didScroll = false, + changeHeaderOn = 200; + function init() { - window.addEventListener( 'scroll', function( event ) { - if( !didScroll ) { + window.addEventListener('scroll', function(event) { + if (!didScroll) { didScroll = true; - setTimeout( scrollPage, 250 ); + setTimeout(scrollPage, 250); } - }, false ); + }, false); } + function scrollPage() { var sy = scrollY(); - if ( sy >= changeHeaderOn ) { + if (sy >= changeHeaderOn) { $(header).addClass('navbar-scroll') - } - else { + } else { $(header).removeClass('navbar-scroll') } didScroll = false; } + function scrollY() { return window.pageYOffset || docElem.scrollTop; } init(); })(); - - -</script> +</script>
\ No newline at end of file diff --git a/utils/test/reporting/pages/bower.json b/utils/test/reporting/pages/bower.json index dd0996d18..bfc4df3d9 100644 --- a/utils/test/reporting/pages/bower.json +++ b/utils/test/reporting/pages/bower.json @@ -1,32 +1,47 @@ { - "name": "opnfv", - "version": "0.0.0", - "dependencies": { - "angular": "^1.4.0", - "bootstrap": "^3.2.0", - "angular-animate": "^1.4.0", - "jquery-slimscroll": "slimscroll#^1.3.8", - "metisMenu": "~2.0.2", - "chosen": "^1.6.2", - "oclazyload": "^1.0.9", - "angular-bootstrap": "~1.1.2", - "angular-ui-router": "~0.2.15", - "angular-resource": "^1.6.0", - "angular-selectize2": "^3.0.1", - "components-font-awesome": "^4.7.0" - }, - "devDependencies": { - "angular-mocks": "^1.4.0" - }, - "appPath": "app", - "moduleName": "opnfvApp", - "overrides": { - "bootstrap": { - "main": [ - "less/bootstrap.less", - "dist/css/bootstrap.css", - "dist/js/bootstrap.js" - ] + "name": "opnfv", + "version": "0.0.0", + "dependencies": { + "angular": "^1.4.0", + "bootstrap": "^3.2.0", + "angular-animate": "^1.4.0", + "jquery-slimscroll": "slimscroll#^1.3.8", + "metisMenu": "~2.0.2", + "chosen": "^1.6.2", + "oclazyload": "^1.0.9", + "angular-bootstrap": "~1.1.2", + "angular-ui-router": "~0.2.15", + "angular-resource": "^1.6.0", + "angular-selectize2": "^3.0.1", + "components-font-awesome": "^4.7.0", + "angular-tooltips": "^1.1.8", + "jQuery-rwdImageMaps": "*", + "animate.css": "^3.5.2", + "ng-dialog": "^1.0.0", + "inspiniacss": "^0.0.1" + }, + "devDependencies": { + "angular-mocks": "^1.4.0" + }, + "appPath": "app", + "moduleName": "opnfvApp", + "overrides": { + "bootstrap": { + "main": [ + "less/bootstrap.less", + "dist/css/bootstrap.css", + "dist/js/bootstrap.js" + ] + }, + "jQuery-rwdImageMaps": { + "main": [ + "jquery.rwdImageMaps.min.js" + ] + }, + "inspiniacss": { + "main": [ + "style.css" + ] + } } - } -} +}
\ No newline at end of file diff --git a/utils/test/reporting/pages/test/karma.conf.js b/utils/test/reporting/pages/test/karma.conf.js index 2b0f41cd3..5c2e79b9f 100644 --- a/utils/test/reporting/pages/test/karma.conf.js +++ b/utils/test/reporting/pages/test/karma.conf.js @@ -36,6 +36,7 @@ module.exports = function(config) { 'bower_components/microplugin/src/microplugin.js', 'bower_components/selectize/dist/js/selectize.js', 'bower_components/angular-selectize2/dist/angular-selectize.js', + 'bower_components/angular-tooltips/dist/angular-tooltips.min.js', 'bower_components/angular-mocks/angular-mocks.js', // endbower 'app/scripts/**/*.js', diff --git a/utils/test/reporting/reporting.yaml b/utils/test/reporting/reporting.yaml index 9db0890b2..8c5ce1383 100644 --- a/utils/test/reporting/reporting.yaml +++ b/utils/test/reporting/reporting.yaml @@ -1,3 +1,4 @@ +--- general: installers: - apex @@ -8,6 +9,7 @@ general: versions: - master + - danube log: log_file: reporting.log @@ -19,12 +21,12 @@ general: directories: # Relative to the path where the repo is cloned: - dir_reporting: utils/tests/reporting/ - dir_log: utils/tests/reporting/log/ - dir_conf: utils/tests/reporting/conf/ - dir_utils: utils/tests/reporting/utils/ - dir_templates: utils/tests/reporting/templates/ - dir_display: utils/tests/reporting/display/ + dir_reporting: utils/tests/reporting/ + dir_log: utils/tests/reporting/log/ + dir_conf: utils/tests/reporting/conf/ + dir_utils: utils/tests/reporting/utils/ + dir_templates: utils/tests/reporting/templates/ + dir_display: utils/tests/reporting/display/ url: testresults.opnfv.org/reporting/ @@ -36,17 +38,32 @@ functest: - ovno - security_scan - rally_sanity + - healthcheck + - odl_netvirt + - aaa + - cloudify_ims + - orchestra_ims + - juju_epc + - orchestra + - promise max_scenario_criteria: 50 test_conf: https://git.opnfv.org/cgit/functest/plain/functest/ci/testcases.yaml log_level: ERROR jenkins_url: https://build.opnfv.org/ci/view/functest/job/ - exclude_noha: False - exclude_virtual: True + exclude_noha: "False" + exclude_virtual: "False" yardstick: test_conf: https://git.opnfv.org/cgit/yardstick/plain/tests/ci/report_config.yaml log_level: ERROR +storperf: + test_list: + - snia_steady_state + log_level: ERROR + qtip: bottleneck: + +vsperf: diff --git a/utils/test/reporting/storperf/reporting-status.py b/utils/test/reporting/storperf/reporting-status.py new file mode 100644 index 000000000..888e339f8 --- /dev/null +++ b/utils/test/reporting/storperf/reporting-status.py @@ -0,0 +1,145 @@ +#!/usr/bin/python +# +# This program and the accompanying materials +# are made available under the terms of the Apache License, Version 2.0 +# which accompanies this distribution, and is available at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +import datetime +import jinja2 +import os + +# manage conf +import utils.reporting_utils as rp_utils + +import utils.scenarioResult as sr + +installers = rp_utils.get_config('general.installers') +versions = rp_utils.get_config('general.versions') +PERIOD = rp_utils.get_config('general.period') + +# Logger +logger = rp_utils.getLogger("Storperf-Status") +reportingDate = datetime.datetime.now().strftime("%Y-%m-%d %H:%M") + +logger.info("*******************************************") +logger.info("* Generating reporting scenario status *") +logger.info("* Data retention = %s days *" % PERIOD) +logger.info("* *") +logger.info("*******************************************") + +# retrieve the list of storperf tests +storperf_tests = rp_utils.get_config('storperf.test_list') +logger.info("Storperf tests: %s" % storperf_tests) + +# For all the versions +for version in versions: + # For all the installers + for installer in installers: + # get scenarios results data + # for the moment we consider only 1 case snia_steady_state + scenario_results = rp_utils.getScenarios("snia_steady_state", + installer, + version) + # logger.info("scenario_results: %s" % scenario_results) + + scenario_stats = rp_utils.getScenarioStats(scenario_results) + logger.info("scenario_stats: %s" % scenario_stats) + items = {} + scenario_result_criteria = {} + + # From each scenarios get results list + for s, s_result in scenario_results.items(): + logger.info("---------------------------------") + logger.info("installer %s, version %s, scenario %s", installer, + version, s) + ten_criteria = len(s_result) + + ten_score = 0 + for v in s_result: + if "PASS" in v['criteria']: + ten_score += 1 + + logger.info("ten_score: %s / %s" % (ten_score, ten_criteria)) + + four_score = 0 + try: + LASTEST_TESTS = rp_utils.get_config( + 'general.nb_iteration_tests_success_criteria') + s_result.sort(key=lambda x: x['start_date']) + four_result = s_result[-LASTEST_TESTS:] + logger.debug("four_result: {}".format(four_result)) + logger.debug("LASTEST_TESTS: {}".format(LASTEST_TESTS)) + # logger.debug("four_result: {}".format(four_result)) + four_criteria = len(four_result) + for v in four_result: + if "PASS" in v['criteria']: + four_score += 1 + logger.info("4 Score: %s / %s " % (four_score, + four_criteria)) + except: + logger.error("Impossible to retrieve the four_score") + + try: + s_status = (four_score * 100) / four_criteria + except: + s_status = 0 + logger.info("Score percent = %s" % str(s_status)) + s_four_score = str(four_score) + '/' + str(four_criteria) + s_ten_score = str(ten_score) + '/' + str(ten_criteria) + s_score_percent = str(s_status) + + logger.debug(" s_status: {}".format(s_status)) + if s_status == 100: + logger.info(">>>>> scenario OK, save the information") + else: + logger.info(">>>> scenario not OK, last 4 iterations = %s, \ + last 10 days = %s" % (s_four_score, s_ten_score)) + + s_url = "" + if len(s_result) > 0: + build_tag = s_result[len(s_result)-1]['build_tag'] + logger.debug("Build tag: %s" % build_tag) + s_url = s_url = rp_utils.getJenkinsUrl(build_tag) + logger.info("last jenkins url: %s" % s_url) + + # Save daily results in a file + path_validation_file = ("./display/" + version + + "/storperf/scenario_history.txt") + + if not os.path.exists(path_validation_file): + with open(path_validation_file, 'w') as f: + info = 'date,scenario,installer,details,score\n' + f.write(info) + + with open(path_validation_file, "a") as f: + info = (reportingDate + "," + s + "," + installer + + "," + s_ten_score + "," + + str(s_score_percent) + "\n") + f.write(info) + + scenario_result_criteria[s] = sr.ScenarioResult(s_status, + s_four_score, + s_ten_score, + s_score_percent, + s_url) + + logger.info("--------------------------") + + templateLoader = jinja2.FileSystemLoader(".") + templateEnv = jinja2.Environment(loader=templateLoader, + autoescape=True) + + TEMPLATE_FILE = "./storperf/template/index-status-tmpl.html" + template = templateEnv.get_template(TEMPLATE_FILE) + + outputText = template.render(scenario_results=scenario_result_criteria, + installer=installer, + period=PERIOD, + version=version, + date=reportingDate) + + with open("./display/" + version + + "/storperf/status-" + installer + ".html", "wb") as fh: + fh.write(outputText) diff --git a/utils/test/reporting/storperf/template/index-status-tmpl.html b/utils/test/reporting/storperf/template/index-status-tmpl.html new file mode 100644 index 000000000..e0fcc6828 --- /dev/null +++ b/utils/test/reporting/storperf/template/index-status-tmpl.html @@ -0,0 +1,111 @@ + <html> + <head> + <meta charset="utf-8"> + <!-- Bootstrap core CSS --> + <link href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.4/css/bootstrap.min.css" rel="stylesheet"> + <link href="../../css/default.css" rel="stylesheet"> + <script type="text/javascript" src="http://ajax.googleapis.com/ajax/libs/jquery/1/jquery.min.js"></script> + <script type="text/javascript" src="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.4/js/bootstrap.min.js"></script> + <script type="text/javascript" src="http://d3js.org/d3.v2.min.js"></script> + <script type="text/javascript" src="../../js/gauge.js"></script> + <script type="text/javascript" src="../../js/trend.js"></script> + <script> + function onDocumentReady() { + // Gauge management + {% for scenario in scenario_results.keys() -%} + var gaugeScenario{{loop.index}} = gauge('#gaugeScenario{{loop.index}}'); + {%- endfor %} + // assign success rate to the gauge + function updateReadings() { + {% for scenario in scenario_results.keys() -%} + gaugeScenario{{loop.index}}.update({{scenario_results[scenario].getScorePercent()}}); + {%- endfor %} + } + updateReadings(); + } + + // trend line management + d3.csv("./scenario_history.txt", function(data) { + // *************************************** + // Create the trend line + {% for scenario in scenario_results.keys() -%} + // for scenario {{scenario}} + // Filter results + var trend{{loop.index}} = data.filter(function(row) { + return row["scenario"]=="{{scenario}}" && row["installer"]=="{{installer}}"; + }) + // Parse the date + trend{{loop.index}}.forEach(function(d) { + d.date = parseDate(d.date); + d.score = +d.score + }); + // Draw the trend line + var mytrend = trend("#trend_svg{{loop.index}}",trend{{loop.index}}) + // **************************************** + {%- endfor %} + }); + if ( !window.isLoaded ) { + window.addEventListener("load", function() { + onDocumentReady(); + }, false); + } else { + onDocumentReady(); + } + </script> + <script type="text/javascript"> + $(document).ready(function (){ + $(".btn-more").click(function() { + $(this).hide(); + $(this).parent().find(".panel-default").show(); + }); + }) + </script> + </head> + <body> + <div class="container"> + <div class="masthead"> + <h3 class="text-muted">Storperf status page ({{version}}, {{date}})</h3> + <nav> + <ul class="nav nav-justified"> + <li class="active"><a href="http://testresults.opnfv.org/reporting/index.html">Home</a></li> + <li><a href="status-apex.html">Apex</a></li> + <li><a href="status-compass.html">Compass</a></li> + <li><a href="status-daisy.html">Daisy</a></li> + <li><a href="status-fuel.html">Fuel</a></li> + <li><a href="status-joid.html">Joid</a></li> + </ul> + </nav> + </div> +<div class="row"> + <div class="col-md-1"></div> + <div class="col-md-10"> + <div class="page-header"> + <h2>{{installer}}</h2> + </div> + + <div class="scenario-overview"> + <div class="panel-heading"><h4><b>List of last scenarios ({{version}}) run over the last {{period}} days </b></h4></div> + <table class="table"> + <tr> + <th width="40%">Scenario</th> + <th width="20%">Status</th> + <th width="20%">Trend</th> + <th width="10%">Last 4 Iterations</th> + <th width="10%">Last 10 Days</th> + </tr> + {% for scenario,result in scenario_results.iteritems() -%} + <tr class="tr-ok"> + <td><a href="{{scenario_results[scenario].getLastUrl()}}">{{scenario}}</a></td> + <td><div id="gaugeScenario{{loop.index}}"></div></td> + <td><div id="trend_svg{{loop.index}}"></div></td> + <td>{{scenario_results[scenario].getFourDaysScore()}}</td> + <td>{{scenario_results[scenario].getTenDaysScore()}}</td> + </tr> + {%- endfor %} + </table> + </div> + + + </div> + <div class="col-md-1"></div> +</div> diff --git a/utils/test/reporting/utils/reporting_utils.py b/utils/test/reporting/utils/reporting_utils.py index fc5d188af..aab7a3f4f 100644 --- a/utils/test/reporting/utils/reporting_utils.py +++ b/utils/test/reporting/utils/reporting_utils.py @@ -101,7 +101,15 @@ def getApiResults(case, installer, scenario, version): def getScenarios(case, installer, version): - case = case.getName() + try: + case = case.getName() + except: + # if case is not an object test case, try the string + if type(case) == str: + case = case + else: + raise ValueError("Case cannot be evaluated") + period = get_config('general.period') url_base = get_config('testapi.url') @@ -269,11 +277,15 @@ def getJenkinsUrl(build_tag): url_base = get_config('functest.jenkins_url') try: build_id = [int(s) for s in build_tag.split("-") if s.isdigit()] - url_id = build_tag[8:-(len(build_id) + 3)] + "/" + str(build_id[0]) + url_id = (build_tag[8:-(len(str(build_id[0])) + 1)] + + "/" + str(build_id[0])) jenkins_url = url_base + url_id + "/console" except: print('Impossible to get jenkins url:') + if "jenkins-" not in build_tag: + jenkins_url = None + return jenkins_url diff --git a/utils/test/reporting/yardstick/scenarioResult.py b/utils/test/reporting/utils/scenarioResult.py index 1f7eb2b24..6029d7f42 100644 --- a/utils/test/reporting/yardstick/scenarioResult.py +++ b/utils/test/reporting/utils/scenarioResult.py @@ -10,11 +10,12 @@ class ScenarioResult(object): def __init__(self, status, four_days_score='', ten_days_score='', - score_percent=0.0): + score_percent=0.0, last_url=''): self.status = status self.four_days_score = four_days_score self.ten_days_score = ten_days_score self.score_percent = score_percent + self.last_url = last_url def getStatus(self): return self.status @@ -27,3 +28,6 @@ class ScenarioResult(object): def getScorePercent(self): return self.score_percent + + def getLastUrl(self): + return self.last_url diff --git a/utils/test/reporting/yardstick/reporting-status.py b/utils/test/reporting/yardstick/reporting-status.py index a0f0b0184..12f42ca31 100644 --- a/utils/test/reporting/yardstick/reporting-status.py +++ b/utils/test/reporting/yardstick/reporting-status.py @@ -10,7 +10,7 @@ import datetime import jinja2 import os -import scenarioResult as sr +import utils.scenarioResult as sr from scenarios import config as cf # manage conf diff --git a/utils/test/testapi/.coveragerc b/utils/test/testapi/.coveragerc new file mode 100644 index 000000000..23fb97fba --- /dev/null +++ b/utils/test/testapi/.coveragerc @@ -0,0 +1,27 @@ +# .coveragerc to control coverage.py + +[run] +branch = True +source = + opnfv_testapi + +[report] +# Regexes for lines to exclude from consideration +exclude_lines = + # Have to re-enable the standard pragma + pragma: no cover + + # Don't complain about missing debug-only code: + def __repr__ + if self\.debug + + # Don't complain if tests don't hit defensive assertion code: + raise AssertionError + raise NotImplementedError + + # Don't complain if non-runnable code isn't run: + if 0: + if __name__ == .__main__.: + +ignore_errors = True + diff --git a/utils/test/testapi/docker/Dockerfile b/utils/test/testapi/docker/Dockerfile index 86513e05b..e031e194c 100644 --- a/utils/test/testapi/docker/Dockerfile +++ b/utils/test/testapi/docker/Dockerfile @@ -8,13 +8,12 @@ # $ docker build -t opnfv/testapi:tag . # # Execution: -# $ docker run -dti -p 8000:8000 \ -# -e "swagger_url=http://10.63.243.17:8000" \ +# $ docker run -dti -p 8001:8000 \ +# -e "swagger_url=http://10.63.243.17:8001" \ # -e "mongodb_url=mongodb://10.63.243.17:27017/" \ -# -e "api_port=8000" # opnfv/testapi:tag # -# NOTE: providing swagger_url, api_port, mongodb_url is optional. +# NOTE: providing swagger_url, mongodb_url is optional. # If not provided, it will use the default one # configured in config.ini # diff --git a/utils/test/testapi/docker/prepare-env.sh b/utils/test/testapi/docker/prepare-env.sh index 99433cc8c..9f07efbd1 100755 --- a/utils/test/testapi/docker/prepare-env.sh +++ b/utils/test/testapi/docker/prepare-env.sh @@ -9,8 +9,3 @@ fi if [ "$swagger_url" != "" ]; then sudo crudini --set --existing $FILE swagger base_url $swagger_url fi - -if [ "$api_port" != "" ];then - sudo crudini --set --existing $FILE api port $api_port -fi - diff --git a/utils/test/testapi/etc/config.ini b/utils/test/testapi/etc/config.ini index 0edb73a3f..77cc6c6ee 100644 --- a/utils/test/testapi/etc/config.ini +++ b/utils/test/testapi/etc/config.ini @@ -11,6 +11,7 @@ dbname = test_results_collection port = 8000 # With debug_on set to true, error traces will be shown in HTTP responses debug = True +authenticate = False [swagger] base_url = http://localhost:8000 diff --git a/utils/test/testapi/opnfv_testapi/cmd/server.py b/utils/test/testapi/opnfv_testapi/cmd/server.py index c3d734607..fa2b72250 100644 --- a/utils/test/testapi/opnfv_testapi/cmd/server.py +++ b/utils/test/testapi/opnfv_testapi/cmd/server.py @@ -30,37 +30,43 @@ TODOs : """ import argparse +import sys -import tornado.ioloop import motor +import tornado.ioloop -from opnfv_testapi.common.config import APIConfig -from opnfv_testapi.tornado_swagger import swagger +from opnfv_testapi.common import config from opnfv_testapi.router import url_mappings +from opnfv_testapi.tornado_swagger import swagger + +CONF = None + -# optionally get config file from command line -parser = argparse.ArgumentParser() -parser.add_argument("-c", "--config-file", dest='config_file', - help="Config file location") -args = parser.parse_args() -CONF = APIConfig().parse(args.config_file) +def parse_config(argv=[]): + global CONF + parser = argparse.ArgumentParser() + parser.add_argument("-c", "--config-file", dest='config_file', + help="Config file location") + args = parser.parse_args(argv) + CONF = config.APIConfig().parse(args.config_file) -# connecting to MongoDB server, and choosing database -client = motor.MotorClient(CONF.mongo_url) -db = client[CONF.mongo_dbname] -swagger.docs(base_url=CONF.swagger_base_url) +def get_db(): + return motor.MotorClient(CONF.mongo_url)[CONF.mongo_dbname] def make_app(): + swagger.docs(base_url=CONF.swagger_base_url) return swagger.Application( url_mappings.mappings, - db=db, + db=get_db(), debug=CONF.api_debug_on, + auth=CONF.api_authenticate_on ) def main(): + parse_config(sys.argv[1:]) application = make_app() application.listen(CONF.api_port) tornado.ioloop.IOLoop.current().start() diff --git a/utils/test/testapi/opnfv_testapi/common/config.py b/utils/test/testapi/opnfv_testapi/common/config.py index ecab88ae3..105d4fabf 100644 --- a/utils/test/testapi/opnfv_testapi/common/config.py +++ b/utils/test/testapi/opnfv_testapi/common/config.py @@ -7,9 +7,8 @@ # http://www.apache.org/licenses/LICENSE-2.0 # feng.xiaowei@zte.com.cn remove prepare_put_request 5-30-2016 ############################################################################## - - -from ConfigParser import SafeConfigParser, NoOptionError +import ConfigParser +import os class ParseError(Exception): @@ -24,7 +23,7 @@ class ParseError(Exception): return 'error parsing config file : %s' % self.msg -class APIConfig: +class APIConfig(object): """ The purpose of this class is to load values correctly from the config file. Each key is declared as an attribute in __init__() and linked in parse() @@ -36,20 +35,21 @@ class APIConfig: self.mongo_dbname = None self.api_port = None self.api_debug_on = None + self.api_authenticate_on = None self._parser = None self.swagger_base_url = None def _get_parameter(self, section, param): try: return self._parser.get(section, param) - except NoOptionError: - raise ParseError("[%s.%s] parameter not found" % (section, param)) + except ConfigParser.NoOptionError: + raise ParseError("No parameter: [%s.%s]" % (section, param)) def _get_int_parameter(self, section, param): try: return int(self._get_parameter(section, param)) except ValueError: - raise ParseError("[%s.%s] not an int" % (section, param)) + raise ParseError("Not int: [%s.%s]" % (section, param)) def _get_bool_parameter(self, section, param): result = self._get_parameter(section, param) @@ -59,7 +59,7 @@ class APIConfig: return False raise ParseError( - "[%s.%s : %s] not a boolean" % (section, param, result)) + "Not boolean: [%s.%s : %s]" % (section, param, result)) @staticmethod def parse(config_location=None): @@ -68,28 +68,21 @@ class APIConfig: if config_location is None: config_location = obj._default_config_location - obj._parser = SafeConfigParser() - obj._parser.read(config_location) - if not obj._parser: + if not os.path.exists(config_location): raise ParseError("%s not found" % config_location) + obj._parser = ConfigParser.SafeConfigParser() + obj._parser.read(config_location) + # Linking attributes to keys from file with their sections obj.mongo_url = obj._get_parameter("mongo", "url") obj.mongo_dbname = obj._get_parameter("mongo", "dbname") obj.api_port = obj._get_int_parameter("api", "port") obj.api_debug_on = obj._get_bool_parameter("api", "debug") + obj.api_authenticate_on = obj._get_bool_parameter("api", + "authenticate") + obj.swagger_base_url = obj._get_parameter("swagger", "base_url") return obj - - def __str__(self): - return "mongo_url = %s \n" \ - "mongo_dbname = %s \n" \ - "api_port = %s \n" \ - "api_debug_on = %s \n" \ - "swagger_base_url = %s \n" % (self.mongo_url, - self.mongo_dbname, - self.api_port, - self.api_debug_on, - self.swagger_base_url) diff --git a/utils/test/testapi/opnfv_testapi/common/constants.py b/utils/test/testapi/opnfv_testapi/common/constants.py index 4d39a142d..71bd95216 100644 --- a/utils/test/testapi/opnfv_testapi/common/constants.py +++ b/utils/test/testapi/opnfv_testapi/common/constants.py @@ -10,6 +10,7 @@ DEFAULT_REPRESENTATION = "application/json" HTTP_BAD_REQUEST = 400 +HTTP_UNAUTHORIZED = 401 HTTP_FORBIDDEN = 403 HTTP_NOT_FOUND = 404 HTTP_OK = 200 diff --git a/utils/test/testapi/opnfv_testapi/resources/handlers.py b/utils/test/testapi/opnfv_testapi/resources/handlers.py index a2628e249..8255b526a 100644 --- a/utils/test/testapi/opnfv_testapi/resources/handlers.py +++ b/utils/test/testapi/opnfv_testapi/resources/handlers.py @@ -20,19 +20,19 @@ # feng.xiaowei@zte.com.cn remove DashboardHandler 5-30-2016 ############################################################################## -import json from datetime import datetime +import functools +import json from tornado import gen -from tornado.web import RequestHandler, asynchronous, HTTPError +from tornado import web -from models import CreateResponse -from opnfv_testapi.common.constants import DEFAULT_REPRESENTATION, \ - HTTP_BAD_REQUEST, HTTP_NOT_FOUND, HTTP_FORBIDDEN +import models +from opnfv_testapi.common import constants from opnfv_testapi.tornado_swagger import swagger -class GenericApiHandler(RequestHandler): +class GenericApiHandler(web.RequestHandler): def __init__(self, application, request, **kwargs): super(GenericApiHandler, self).__init__(application, request, **kwargs) self.db = self.settings["db"] @@ -44,49 +44,71 @@ class GenericApiHandler(RequestHandler): self.db_testcases = 'testcases' self.db_results = 'results' self.db_scenarios = 'scenarios' + self.auth = self.settings["auth"] def prepare(self): if self.request.method != "GET" and self.request.method != "DELETE": if self.request.headers.get("Content-Type") is not None: if self.request.headers["Content-Type"].startswith( - DEFAULT_REPRESENTATION): + constants.DEFAULT_REPRESENTATION): try: self.json_args = json.loads(self.request.body) except (ValueError, KeyError, TypeError) as error: - raise HTTPError(HTTP_BAD_REQUEST, - "Bad Json format [{}]". - format(error)) + raise web.HTTPError(constants.HTTP_BAD_REQUEST, + "Bad Json format [{}]". + format(error)) def finish_request(self, json_object=None): if json_object: self.write(json.dumps(json_object)) - self.set_header("Content-Type", DEFAULT_REPRESENTATION) + self.set_header("Content-Type", constants.DEFAULT_REPRESENTATION) self.finish() def _create_response(self, resource): href = self.request.full_url() + '/' + str(resource) - return CreateResponse(href=href).format() + return models.CreateResponse(href=href).format() def format_data(self, data): cls_data = self.table_cls.from_dict(data) return cls_data.format_http() - @asynchronous + def authenticate(method): + @web.asynchronous + @gen.coroutine + @functools.wraps(method) + def wrapper(self, *args, **kwargs): + if self.auth: + try: + token = self.request.headers['X-Auth-Token'] + except KeyError: + raise web.HTTPError(constants.HTTP_UNAUTHORIZED, + "No Authentication Header.") + query = {'access_token': token} + check = yield self._eval_db_find_one(query, 'tokens') + if not check: + raise web.HTTPError(constants.HTTP_FORBIDDEN, + "Invalid Token.") + ret = yield gen.coroutine(method)(self, *args, **kwargs) + raise gen.Return(ret) + return wrapper + + @web.asynchronous @gen.coroutine + @authenticate def _create(self, miss_checks, db_checks, **kwargs): """ :param miss_checks: [miss1, miss2] :param db_checks: [(table, exist, query, error)] """ if self.json_args is None: - raise HTTPError(HTTP_BAD_REQUEST, "no body") + raise web.HTTPError(constants.HTTP_BAD_REQUEST, "no body") data = self.table_cls.from_dict(self.json_args) for miss in miss_checks: miss_data = data.__getattribute__(miss) if miss_data is None or miss_data == '': - raise HTTPError(HTTP_BAD_REQUEST, - '{} missing'.format(miss)) + raise web.HTTPError(constants.HTTP_BAD_REQUEST, + '{} missing'.format(miss)) for k, v in kwargs.iteritems(): data.__setattr__(k, v) @@ -95,7 +117,7 @@ class GenericApiHandler(RequestHandler): check = yield self._eval_db_find_one(query(data), table) if (exist and not check) or (not exist and check): code, message = error(data) - raise HTTPError(code, message) + raise web.HTTPError(code, message) if self.table != 'results': data.creation_date = datetime.now() @@ -107,7 +129,7 @@ class GenericApiHandler(RequestHandler): resource = _id self.finish_request(self._create_response(resource)) - @asynchronous + @web.asynchronous @gen.coroutine def _list(self, query=None, res_op=None, *args, **kwargs): if query is None: @@ -126,40 +148,42 @@ class GenericApiHandler(RequestHandler): res = res_op(data, *args) self.finish_request(res) - @asynchronous + @web.asynchronous @gen.coroutine def _get_one(self, query): data = yield self._eval_db_find_one(query) if data is None: - raise HTTPError(HTTP_NOT_FOUND, - "[{}] not exist in table [{}]" - .format(query, self.table)) + raise web.HTTPError(constants.HTTP_NOT_FOUND, + "[{}] not exist in table [{}]" + .format(query, self.table)) self.finish_request(self.format_data(data)) - @asynchronous + @web.asynchronous @gen.coroutine + @authenticate def _delete(self, query): data = yield self._eval_db_find_one(query) if data is None: - raise HTTPError(HTTP_NOT_FOUND, - "[{}] not exit in table [{}]" - .format(query, self.table)) + raise web.HTTPError(constants.HTTP_NOT_FOUND, + "[{}] not exit in table [{}]" + .format(query, self.table)) yield self._eval_db(self.table, 'remove', query) self.finish_request() - @asynchronous + @web.asynchronous @gen.coroutine + @authenticate def _update(self, query, db_keys): if self.json_args is None: - raise HTTPError(HTTP_BAD_REQUEST, "No payload") + raise web.HTTPError(constants.HTTP_BAD_REQUEST, "No payload") # check old data exist from_data = yield self._eval_db_find_one(query) if from_data is None: - raise HTTPError(HTTP_NOT_FOUND, - "{} could not be found in table [{}]" - .format(query, self.table)) + raise web.HTTPError(constants.HTTP_NOT_FOUND, + "{} could not be found in table [{}]" + .format(query, self.table)) data = self.table_cls.from_dict(from_data) # check new data exist @@ -167,9 +191,9 @@ class GenericApiHandler(RequestHandler): if not equal: to_data = yield self._eval_db_find_one(new_query) if to_data is not None: - raise HTTPError(HTTP_FORBIDDEN, - "{} already exists in table [{}]" - .format(new_query, self.table)) + raise web.HTTPError(constants.HTTP_FORBIDDEN, + "{} already exists in table [{}]" + .format(new_query, self.table)) # we merge the whole document """ edit_request = self._update_requests(data) @@ -186,7 +210,7 @@ class GenericApiHandler(RequestHandler): request = self._update_request(request, k, v, data.__getattribute__(k)) if not request: - raise HTTPError(HTTP_FORBIDDEN, "Nothing to update") + raise web.HTTPError(constants.HTTP_FORBIDDEN, "Nothing to update") edit_request = data.format() edit_request.update(request) diff --git a/utils/test/testapi/opnfv_testapi/resources/models.py b/utils/test/testapi/opnfv_testapi/resources/models.py index f518c97a0..0ea482fd2 100644 --- a/utils/test/testapi/opnfv_testapi/resources/models.py +++ b/utils/test/testapi/opnfv_testapi/resources/models.py @@ -1,98 +1,116 @@ -##############################################################################
-# Copyright (c) 2015 Orange
-# guyrodrigue.koffi@orange.com / koffirodrigue@gmail.com
-# All rights reserved. This program and the accompanying materials
-# are made available under the terms of the Apache License, Version 2.0
-# which accompanies this distribution, and is available at
-# http://www.apache.org/licenses/LICENSE-2.0
-# feng.xiaowei@zte.com.cn mv Pod to pod_models.py 5-18-2016
-# feng.xiaowei@zte.com.cn add MetaCreateResponse/MetaGetResponse 5-18-2016
-# feng.xiaowei@zte.com.cn mv TestProject to project_models.py 5-19-2016
-# feng.xiaowei@zte.com.cn delete meta class 5-19-2016
-# feng.xiaowei@zte.com.cn add CreateResponse 5-19-2016
-# feng.xiaowei@zte.com.cn mv TestCase to testcase_models.py 5-20-2016
-# feng.xiaowei@zte.com.cn mv TestResut to result_models.py 5-23-2016
-# feng.xiaowei@zte.com.cn add ModelBase 12-20-2016
-##############################################################################
-import copy
-
-from opnfv_testapi.tornado_swagger import swagger
-
-
-class ModelBase(object):
-
- def _format(self, excludes):
- new_obj = copy.deepcopy(self)
- dicts = new_obj.__dict__
- for k in dicts.keys():
- if k in excludes:
- del dicts[k]
- elif dicts[k]:
- if hasattr(dicts[k], 'format'):
- dicts[k] = dicts[k].format()
- elif isinstance(dicts[k], list):
- hs = list()
- [hs.append(h.format() if hasattr(h, 'format') else str(h))
- for h in dicts[k]]
- dicts[k] = hs
- elif not isinstance(dicts[k], (str, int, float, dict)):
- dicts[k] = str(dicts[k])
- return dicts
-
- def format(self):
- return self._format(['_id'])
-
- def format_http(self):
- return self._format([])
-
- @staticmethod
- def attr_parser():
- return {}
-
- @classmethod
- def from_dict(cls, a_dict):
- if a_dict is None:
- return None
-
- attr_parser = cls.attr_parser()
- t = cls()
- for k, v in a_dict.iteritems():
- value = v
- if isinstance(v, dict) and k in attr_parser:
- value = attr_parser[k].from_dict(v)
- elif isinstance(v, list) and k in attr_parser:
- value = []
- for item in v:
- value.append(attr_parser[k].from_dict(item))
-
- t.__setattr__(k, value)
-
- return t
-
-
-@swagger.model()
-class CreateResponse(ModelBase):
- def __init__(self, href=''):
- self.href = href
-
-
-@swagger.model()
-class Versions(ModelBase):
- """
- @property versions:
- @ptype versions: C{list} of L{Version}
- """
-
- def __init__(self):
- self.versions = list()
-
- @staticmethod
- def attr_parser():
- return {'versions': Version}
-
-
-@swagger.model()
-class Version(ModelBase):
- def __init__(self, version=None, description=None):
- self.version = version
- self.description = description
+############################################################################## +# Copyright (c) 2015 Orange +# guyrodrigue.koffi@orange.com / koffirodrigue@gmail.com +# All rights reserved. This program and the accompanying materials +# are made available under the terms of the Apache License, Version 2.0 +# which accompanies this distribution, and is available at +# http://www.apache.org/licenses/LICENSE-2.0 +# feng.xiaowei@zte.com.cn mv Pod to pod_models.py 5-18-2016 +# feng.xiaowei@zte.com.cn add MetaCreateResponse/MetaGetResponse 5-18-2016 +# feng.xiaowei@zte.com.cn mv TestProject to project_models.py 5-19-2016 +# feng.xiaowei@zte.com.cn delete meta class 5-19-2016 +# feng.xiaowei@zte.com.cn add CreateResponse 5-19-2016 +# feng.xiaowei@zte.com.cn mv TestCase to testcase_models.py 5-20-2016 +# feng.xiaowei@zte.com.cn mv TestResut to result_models.py 5-23-2016 +# feng.xiaowei@zte.com.cn add ModelBase 12-20-2016 +############################################################################## +import copy +import ast + + +from opnfv_testapi.tornado_swagger import swagger + + +class ModelBase(object): + + def format(self): + return self._format(['_id']) + + def format_http(self): + return self._format([]) + + @classmethod + def from_dict(cls, a_dict): + if a_dict is None: + return None + + attr_parser = cls.attr_parser() + t = cls() + for k, v in a_dict.iteritems(): + value = v + if isinstance(v, dict) and k in attr_parser: + value = attr_parser[k].from_dict(v) + elif isinstance(v, list) and k in attr_parser: + value = [] + for item in v: + value.append(attr_parser[k].from_dict(item)) + + t.__setattr__(k, value) + + return t + + @staticmethod + def attr_parser(): + return {} + + def _format(self, excludes): + new_obj = copy.deepcopy(self) + dicts = new_obj.__dict__ + for k in dicts.keys(): + if k in excludes: + del dicts[k] + elif dicts[k]: + dicts[k] = self._obj_format(dicts[k]) + return dicts + + def _obj_format(self, obj): + if self._has_format(obj): + obj = obj.format() + elif isinstance(obj, unicode): + try: + obj = self._obj_format(ast.literal_eval(obj)) + except: + try: + obj = str(obj) + except: + obj = obj + elif isinstance(obj, list): + hs = list() + for h in obj: + hs.append(self._obj_format(h)) + obj = hs + elif not isinstance(obj, (str, int, float, dict)): + obj = str(obj) + return obj + + @staticmethod + def _has_format(obj): + return not isinstance(obj, (str, unicode)) and hasattr(obj, 'format') + + +@swagger.model() +class CreateResponse(ModelBase): + def __init__(self, href=''): + self.href = href + + +@swagger.model() +class Versions(ModelBase): + """ + @property versions: + @ptype versions: C{list} of L{Version} + """ + + def __init__(self): + self.versions = list() + + @staticmethod + def attr_parser(): + return {'versions': Version} + + +@swagger.model() +class Version(ModelBase): + def __init__(self, version=None, description=None): + self.version = version + self.description = description diff --git a/utils/test/testapi/opnfv_testapi/resources/pod_handlers.py b/utils/test/testapi/opnfv_testapi/resources/pod_handlers.py index e1bd9d359..65c27f60a 100644 --- a/utils/test/testapi/opnfv_testapi/resources/pod_handlers.py +++ b/utils/test/testapi/opnfv_testapi/resources/pod_handlers.py @@ -6,17 +6,17 @@ # which accompanies this distribution, and is available at # http://www.apache.org/licenses/LICENSE-2.0 ############################################################################## +import handlers +from opnfv_testapi.common import constants from opnfv_testapi.tornado_swagger import swagger -from handlers import GenericApiHandler -from pod_models import Pod -from opnfv_testapi.common.constants import HTTP_FORBIDDEN +import pod_models -class GenericPodHandler(GenericApiHandler): +class GenericPodHandler(handlers.GenericApiHandler): def __init__(self, application, request, **kwargs): super(GenericPodHandler, self).__init__(application, request, **kwargs) self.table = 'pods' - self.table_cls = Pod + self.table_cls = pod_models.Pod class PodCLHandler(GenericPodHandler): @@ -46,7 +46,7 @@ class PodCLHandler(GenericPodHandler): def error(data): message = '{} already exists as a pod'.format(data.name) - return HTTP_FORBIDDEN, message + return constants.HTTP_FORBIDDEN, message miss_checks = ['name'] db_checks = [(self.table, False, query, error)] diff --git a/utils/test/testapi/opnfv_testapi/resources/project_handlers.py b/utils/test/testapi/opnfv_testapi/resources/project_handlers.py index 94c65b722..f3521961d 100644 --- a/utils/test/testapi/opnfv_testapi/resources/project_handlers.py +++ b/utils/test/testapi/opnfv_testapi/resources/project_handlers.py @@ -6,19 +6,19 @@ # which accompanies this distribution, and is available at # http://www.apache.org/licenses/LICENSE-2.0 ############################################################################## +import handlers +from opnfv_testapi.common import constants from opnfv_testapi.tornado_swagger import swagger -from handlers import GenericApiHandler -from opnfv_testapi.common.constants import HTTP_FORBIDDEN -from project_models import Project +import project_models -class GenericProjectHandler(GenericApiHandler): +class GenericProjectHandler(handlers.GenericApiHandler): def __init__(self, application, request, **kwargs): super(GenericProjectHandler, self).__init__(application, request, **kwargs) self.table = 'projects' - self.table_cls = Project + self.table_cls = project_models.Project class ProjectCLHandler(GenericProjectHandler): @@ -48,7 +48,7 @@ class ProjectCLHandler(GenericProjectHandler): def error(data): message = '{} already exists as a project'.format(data.name) - return HTTP_FORBIDDEN, message + return constants.HTTP_FORBIDDEN, message miss_checks = ['name'] db_checks = [(self.table, False, query, error)] diff --git a/utils/test/testapi/opnfv_testapi/resources/result_handlers.py b/utils/test/testapi/opnfv_testapi/resources/result_handlers.py index 2a1ed56ee..d41ba4820 100644 --- a/utils/test/testapi/opnfv_testapi/resources/result_handlers.py +++ b/utils/test/testapi/opnfv_testapi/resources/result_handlers.py @@ -6,30 +6,32 @@ # which accompanies this distribution, and is available at # http://www.apache.org/licenses/LICENSE-2.0 ############################################################################## -from datetime import datetime, timedelta +from datetime import datetime +from datetime import timedelta -from bson.objectid import ObjectId -from tornado.web import HTTPError +from bson import objectid +from tornado import web -from opnfv_testapi.common.constants import HTTP_BAD_REQUEST, HTTP_NOT_FOUND -from opnfv_testapi.resources.handlers import GenericApiHandler -from opnfv_testapi.resources.result_models import TestResult +from opnfv_testapi.common import constants +from opnfv_testapi.resources import handlers +from opnfv_testapi.resources import result_models from opnfv_testapi.tornado_swagger import swagger -class GenericResultHandler(GenericApiHandler): +class GenericResultHandler(handlers.GenericApiHandler): def __init__(self, application, request, **kwargs): super(GenericResultHandler, self).__init__(application, request, **kwargs) self.table = self.db_results - self.table_cls = TestResult + self.table_cls = result_models.TestResult def get_int(self, key, value): try: value = int(value) except: - raise HTTPError(HTTP_BAD_REQUEST, '{} must be int'.format(key)) + raise web.HTTPError(constants.HTTP_BAD_REQUEST, + '{} must be int'.format(key)) return value def set_query(self): @@ -144,14 +146,14 @@ class ResultsCLHandler(GenericResultHandler): def pod_error(data): message = 'Could not find pod [{}]'.format(data.pod_name) - return HTTP_NOT_FOUND, message + return constants.HTTP_NOT_FOUND, message def project_query(data): return {'name': data.project_name} def project_error(data): message = 'Could not find project [{}]'.format(data.project_name) - return HTTP_NOT_FOUND, message + return constants.HTTP_NOT_FOUND, message def testcase_query(data): return {'project_name': data.project_name, 'name': data.case_name} @@ -159,7 +161,7 @@ class ResultsCLHandler(GenericResultHandler): def testcase_error(data): message = 'Could not find testcase [{}] in project [{}]'\ .format(data.case_name, data.project_name) - return HTTP_NOT_FOUND, message + return constants.HTTP_NOT_FOUND, message miss_checks = ['pod_name', 'project_name', 'case_name'] db_checks = [('pods', True, pod_query, pod_error), @@ -178,7 +180,7 @@ class ResultsGURHandler(GenericResultHandler): @raise 404: test result not exist """ query = dict() - query["_id"] = ObjectId(result_id) + query["_id"] = objectid.ObjectId(result_id) self._get_one(query) @swagger.operation(nickname="updateTestResultById") @@ -193,6 +195,6 @@ class ResultsGURHandler(GenericResultHandler): @raise 404: result not exist @raise 403: nothing to update """ - query = {'_id': ObjectId(result_id)} + query = {'_id': objectid.ObjectId(result_id)} db_keys = [] self._update(query, db_keys) diff --git a/utils/test/testapi/opnfv_testapi/resources/scenario_handlers.py b/utils/test/testapi/opnfv_testapi/resources/scenario_handlers.py index a8c1a94fe..083bf59fc 100644 --- a/utils/test/testapi/opnfv_testapi/resources/scenario_handlers.py +++ b/utils/test/testapi/opnfv_testapi/resources/scenario_handlers.py @@ -1,17 +1,16 @@ -from opnfv_testapi.common.constants import HTTP_FORBIDDEN -from opnfv_testapi.resources.handlers import GenericApiHandler -from opnfv_testapi.resources.scenario_models import Scenario +from opnfv_testapi.common import constants +from opnfv_testapi.resources import handlers import opnfv_testapi.resources.scenario_models as models from opnfv_testapi.tornado_swagger import swagger -class GenericScenarioHandler(GenericApiHandler): +class GenericScenarioHandler(handlers.GenericApiHandler): def __init__(self, application, request, **kwargs): super(GenericScenarioHandler, self).__init__(application, request, **kwargs) self.table = self.db_scenarios - self.table_cls = Scenario + self.table_cls = models.Scenario class ScenariosCLHandler(GenericScenarioHandler): @@ -81,7 +80,7 @@ class ScenariosCLHandler(GenericScenarioHandler): def error(data): message = '{} already exists as a scenario'.format(data.name) - return HTTP_FORBIDDEN, message + return constants.HTTP_FORBIDDEN, message miss_checks = ['name'] db_checks = [(self.table, False, query, error)] @@ -116,6 +115,17 @@ class ScenarioGURHandler(GenericScenarioHandler): db_keys = ['name'] self._update(query, db_keys) + @swagger.operation(nickname="deleteScenarioByName") + def delete(self, name): + """ + @description: delete a scenario by name + @return 200: delete success + @raise 404: scenario not exist: + """ + + query = {'name': name} + self._delete(query) + def _update_query(self, keys, data): query = dict() equal = True diff --git a/utils/test/testapi/opnfv_testapi/resources/scenario_models.py b/utils/test/testapi/opnfv_testapi/resources/scenario_models.py index 73bcbe99e..b84accf4d 100644 --- a/utils/test/testapi/opnfv_testapi/resources/scenario_models.py +++ b/utils/test/testapi/opnfv_testapi/resources/scenario_models.py @@ -49,6 +49,24 @@ class ScenarioProject(models.ModelBase): return {'scores': ScenarioScore, 'trust_indicators': ScenarioTI} + def __eq__(self, other): + return [self.project == other.project and + self._customs_eq(other) and + self._scores_eq(other) and + self._ti_eq(other)] + + def __ne__(self, other): + return not self.__eq__(other) + + def _customs_eq(self, other): + return set(self.customs) == set(other.customs) + + def _scores_eq(self, other): + return set(self.scores) == set(other.scores) + + def _ti_eq(self, other): + return set(self.trust_indicators) == set(other.trust_indicators) + @swagger.model() class ScenarioVersion(models.ModelBase): @@ -64,6 +82,21 @@ class ScenarioVersion(models.ModelBase): def attr_parser(): return {'projects': ScenarioProject} + def __eq__(self, other): + return [self.version == other.version and self._projects_eq(other)] + + def __ne__(self, other): + return not self.__eq__(other) + + def _projects_eq(self, other): + for s_project in self.projects: + for o_project in other.projects: + if s_project.project == o_project.project: + if s_project != o_project: + return False + + return True + @swagger.model() class ScenarioInstaller(models.ModelBase): @@ -79,6 +112,21 @@ class ScenarioInstaller(models.ModelBase): def attr_parser(): return {'versions': ScenarioVersion} + def __eq__(self, other): + return [self.installer == other.installer and self._versions_eq(other)] + + def __ne__(self, other): + return not self.__eq__(other) + + def _versions_eq(self, other): + for s_version in self.versions: + for o_version in other.versions: + if s_version.version == o_version.version: + if s_version != o_version: + return False + + return True + @swagger.model() class ScenarioCreateRequest(models.ModelBase): @@ -126,6 +174,21 @@ class Scenario(models.ModelBase): def attr_parser(): return {'installers': ScenarioInstaller} + def __ne__(self, other): + return not self.__eq__(other) + + def __eq__(self, other): + return [self.name == other.name and self._installers_eq(other)] + + def _installers_eq(self, other): + for s_install in self.installers: + for o_install in other.installers: + if s_install.installer == o_install.installer: + if s_install != o_install: + return False + + return True + @swagger.model() class Scenarios(models.ModelBase): diff --git a/utils/test/testapi/opnfv_testapi/resources/testcase_handlers.py b/utils/test/testapi/opnfv_testapi/resources/testcase_handlers.py index 100a4fd91..3debd6918 100644 --- a/utils/test/testapi/opnfv_testapi/resources/testcase_handlers.py +++ b/utils/test/testapi/opnfv_testapi/resources/testcase_handlers.py @@ -6,19 +6,19 @@ # which accompanies this distribution, and is available at # http://www.apache.org/licenses/LICENSE-2.0 ############################################################################## -from opnfv_testapi.common.constants import HTTP_FORBIDDEN -from opnfv_testapi.resources.handlers import GenericApiHandler -from opnfv_testapi.resources.testcase_models import Testcase +from opnfv_testapi.common import constants +from opnfv_testapi.resources import handlers +from opnfv_testapi.resources import testcase_models from opnfv_testapi.tornado_swagger import swagger -class GenericTestcaseHandler(GenericApiHandler): +class GenericTestcaseHandler(handlers.GenericApiHandler): def __init__(self, application, request, **kwargs): super(GenericTestcaseHandler, self).__init__(application, request, **kwargs) self.table = self.db_testcases - self.table_cls = Testcase + self.table_cls = testcase_models.Testcase class TestcaseCLHandler(GenericTestcaseHandler): @@ -58,12 +58,12 @@ class TestcaseCLHandler(GenericTestcaseHandler): def p_error(data): message = 'Could not find project [{}]'.format(data.project_name) - return HTTP_FORBIDDEN, message + return constants.HTTP_FORBIDDEN, message def tc_error(data): message = '{} already exists as a testcase in project {}'\ .format(data.name, data.project_name) - return HTTP_FORBIDDEN, message + return constants.HTTP_FORBIDDEN, message miss_checks = ['name'] db_checks = [(self.db_projects, True, p_query, p_error), diff --git a/utils/test/testapi/opnfv_testapi/router/url_mappings.py b/utils/test/testapi/opnfv_testapi/router/url_mappings.py index 0ae3c31c3..39cf006af 100644 --- a/utils/test/testapi/opnfv_testapi/router/url_mappings.py +++ b/utils/test/testapi/opnfv_testapi/router/url_mappings.py @@ -6,37 +6,34 @@ # which accompanies this distribution, and is available at # http://www.apache.org/licenses/LICENSE-2.0 ############################################################################## -from opnfv_testapi.resources.handlers import VersionHandler -from opnfv_testapi.resources.testcase_handlers import TestcaseCLHandler, \ - TestcaseGURHandler -from opnfv_testapi.resources.pod_handlers import PodCLHandler, PodGURHandler -from opnfv_testapi.resources.project_handlers import ProjectCLHandler, \ - ProjectGURHandler -from opnfv_testapi.resources.result_handlers import ResultsCLHandler, \ - ResultsGURHandler -from opnfv_testapi.resources.scenario_handlers import ScenariosCLHandler -from opnfv_testapi.resources.scenario_handlers import ScenarioGURHandler +from opnfv_testapi.resources import handlers +from opnfv_testapi.resources import pod_handlers +from opnfv_testapi.resources import project_handlers +from opnfv_testapi.resources import result_handlers +from opnfv_testapi.resources import scenario_handlers +from opnfv_testapi.resources import testcase_handlers mappings = [ # GET /versions => GET API version - (r"/versions", VersionHandler), + (r"/versions", handlers.VersionHandler), # few examples: # GET /api/v1/pods => Get all pods # GET /api/v1/pods/1 => Get details on POD 1 - (r"/api/v1/pods", PodCLHandler), - (r"/api/v1/pods/([^/]+)", PodGURHandler), + (r"/api/v1/pods", pod_handlers.PodCLHandler), + (r"/api/v1/pods/([^/]+)", pod_handlers.PodGURHandler), # few examples: # GET /projects # GET /projects/yardstick - (r"/api/v1/projects", ProjectCLHandler), - (r"/api/v1/projects/([^/]+)", ProjectGURHandler), + (r"/api/v1/projects", project_handlers.ProjectCLHandler), + (r"/api/v1/projects/([^/]+)", project_handlers.ProjectGURHandler), # few examples # GET /projects/qtip/cases => Get cases for qtip - (r"/api/v1/projects/([^/]+)/cases", TestcaseCLHandler), - (r"/api/v1/projects/([^/]+)/cases/([^/]+)", TestcaseGURHandler), + (r"/api/v1/projects/([^/]+)/cases", testcase_handlers.TestcaseCLHandler), + (r"/api/v1/projects/([^/]+)/cases/([^/]+)", + testcase_handlers.TestcaseGURHandler), # new path to avoid a long depth # GET /results?project=functest&case=keystone.catalog&pod=1 @@ -44,10 +41,10 @@ mappings = [ # POST /results => # Push results with mandatory request payload parameters # (project, case, and pod) - (r"/api/v1/results", ResultsCLHandler), - (r"/api/v1/results/([^/]+)", ResultsGURHandler), + (r"/api/v1/results", result_handlers.ResultsCLHandler), + (r"/api/v1/results/([^/]+)", result_handlers.ResultsGURHandler), # scenarios - (r"/api/v1/scenarios", ScenariosCLHandler), - (r"/api/v1/scenarios/([^/]+)", ScenarioGURHandler), + (r"/api/v1/scenarios", scenario_handlers.ScenariosCLHandler), + (r"/api/v1/scenarios/([^/]+)", scenario_handlers.ScenarioGURHandler), ] diff --git a/utils/test/testapi/opnfv_testapi/tests/unit/common/__init__.py b/utils/test/testapi/opnfv_testapi/tests/unit/common/__init__.py new file mode 100644 index 000000000..e69de29bb --- /dev/null +++ b/utils/test/testapi/opnfv_testapi/tests/unit/common/__init__.py diff --git a/utils/test/testapi/opnfv_testapi/tests/unit/common/noparam.ini b/utils/test/testapi/opnfv_testapi/tests/unit/common/noparam.ini new file mode 100644 index 000000000..fda2a09e9 --- /dev/null +++ b/utils/test/testapi/opnfv_testapi/tests/unit/common/noparam.ini @@ -0,0 +1,16 @@ +# to add a new parameter in the config file, +# the CONF object in config.ini must be updated +[mongo] +# URL of the mongo DB +# Mongo auth url => mongodb://user1:pwd1@host1/?authSource=db1 +url = mongodb://127.0.0.1:27017/ + +[api] +# Listening port +port = 8000 +# With debug_on set to true, error traces will be shown in HTTP responses +debug = True +authenticate = False + +[swagger] +base_url = http://localhost:8000 diff --git a/utils/test/testapi/opnfv_testapi/tests/unit/common/normal.ini b/utils/test/testapi/opnfv_testapi/tests/unit/common/normal.ini new file mode 100644 index 000000000..77cc6c6ee --- /dev/null +++ b/utils/test/testapi/opnfv_testapi/tests/unit/common/normal.ini @@ -0,0 +1,17 @@ +# to add a new parameter in the config file, +# the CONF object in config.ini must be updated +[mongo] +# URL of the mongo DB +# Mongo auth url => mongodb://user1:pwd1@host1/?authSource=db1 +url = mongodb://127.0.0.1:27017/ +dbname = test_results_collection + +[api] +# Listening port +port = 8000 +# With debug_on set to true, error traces will be shown in HTTP responses +debug = True +authenticate = False + +[swagger] +base_url = http://localhost:8000 diff --git a/utils/test/testapi/opnfv_testapi/tests/unit/common/nosection.ini b/utils/test/testapi/opnfv_testapi/tests/unit/common/nosection.ini new file mode 100644 index 000000000..9988fc0a4 --- /dev/null +++ b/utils/test/testapi/opnfv_testapi/tests/unit/common/nosection.ini @@ -0,0 +1,11 @@ +# to add a new parameter in the config file, +# the CONF object in config.ini must be updated +[api] +# Listening port +port = 8000 +# With debug_on set to true, error traces will be shown in HTTP responses +debug = True +authenticate = False + +[swagger] +base_url = http://localhost:8000 diff --git a/utils/test/testapi/opnfv_testapi/tests/unit/common/notboolean.ini b/utils/test/testapi/opnfv_testapi/tests/unit/common/notboolean.ini new file mode 100644 index 000000000..b3f327670 --- /dev/null +++ b/utils/test/testapi/opnfv_testapi/tests/unit/common/notboolean.ini @@ -0,0 +1,17 @@ +# to add a new parameter in the config file, +# the CONF object in config.ini must be updated +[mongo] +# URL of the mongo DB +# Mongo auth url => mongodb://user1:pwd1@host1/?authSource=db1 +url = mongodb://127.0.0.1:27017/ +dbname = test_results_collection + +[api] +# Listening port +port = 8000 +# With debug_on set to true, error traces will be shown in HTTP responses +debug = True +authenticate = notboolean + +[swagger] +base_url = http://localhost:8000 diff --git a/utils/test/testapi/opnfv_testapi/tests/unit/common/notint.ini b/utils/test/testapi/opnfv_testapi/tests/unit/common/notint.ini new file mode 100644 index 000000000..d1b752a34 --- /dev/null +++ b/utils/test/testapi/opnfv_testapi/tests/unit/common/notint.ini @@ -0,0 +1,17 @@ +# to add a new parameter in the config file, +# the CONF object in config.ini must be updated +[mongo] +# URL of the mongo DB +# Mongo auth url => mongodb://user1:pwd1@host1/?authSource=db1 +url = mongodb://127.0.0.1:27017/ +dbname = test_results_collection + +[api] +# Listening port +port = notint +# With debug_on set to true, error traces will be shown in HTTP responses +debug = True +authenticate = False + +[swagger] +base_url = http://localhost:8000 diff --git a/utils/test/testapi/opnfv_testapi/tests/unit/common/test_config.py b/utils/test/testapi/opnfv_testapi/tests/unit/common/test_config.py new file mode 100644 index 000000000..aaff6bb91 --- /dev/null +++ b/utils/test/testapi/opnfv_testapi/tests/unit/common/test_config.py @@ -0,0 +1,36 @@ +import ConfigParser +import os + +import pytest + +from opnfv_testapi.common import config + + +@pytest.fixture() +def config_dir(): + return os.path.dirname(__file__) + + +@pytest.mark.parametrize('exception, config_file, excepted', [ + (config.ParseError, None, '/etc/opnfv_testapi/config.ini not found'), + (ConfigParser.NoSectionError, 'nosection.ini', 'No section:'), + (config.ParseError, 'noparam.ini', 'No parameter:'), + (config.ParseError, 'notint.ini', 'Not int:'), + (config.ParseError, 'notboolean.ini', 'Not boolean:')]) +def pytest_config_exceptions(config_dir, exception, config_file, excepted): + file = '{}/{}'.format(config_dir, config_file) if config_file else None + with pytest.raises(exception) as error: + config.APIConfig().parse(file) + assert excepted in str(error.value) + + +def test_config_success(): + config_dir = os.path.join(os.path.dirname(__file__), + '../../../../etc/config.ini') + conf = config.APIConfig().parse(config_dir) + assert conf.mongo_url == 'mongodb://127.0.0.1:27017/' + assert conf.mongo_dbname == 'test_results_collection' + assert conf.api_port == 8000 + assert conf.api_debug_on is True + assert conf.api_authenticate_on is False + assert conf.swagger_base_url == 'http://localhost:8000' diff --git a/utils/test/testapi/opnfv_testapi/tests/unit/fake_pymongo.py b/utils/test/testapi/opnfv_testapi/tests/unit/fake_pymongo.py index 3c4fd01a3..ef74a0857 100644 --- a/utils/test/testapi/opnfv_testapi/tests/unit/fake_pymongo.py +++ b/utils/test/testapi/opnfv_testapi/tests/unit/fake_pymongo.py @@ -242,3 +242,4 @@ projects = MemDb('projects') testcases = MemDb('testcases') results = MemDb('results') scenarios = MemDb('scenarios') +tokens = MemDb('tokens') diff --git a/utils/test/testapi/opnfv_testapi/tests/unit/test_base.py b/utils/test/testapi/opnfv_testapi/tests/unit/test_base.py index fc780e44c..b955f4a5a 100644 --- a/utils/test/testapi/opnfv_testapi/tests/unit/test_base.py +++ b/utils/test/testapi/opnfv_testapi/tests/unit/test_base.py @@ -7,21 +7,23 @@ # http://www.apache.org/licenses/LICENSE-2.0 ############################################################################## import json +from os import path -from tornado.web import Application -from tornado.testing import AsyncHTTPTestCase +import mock +from tornado import testing -from opnfv_testapi.router import url_mappings -from opnfv_testapi.resources.models import CreateResponse import fake_pymongo +from opnfv_testapi.cmd import server +from opnfv_testapi.resources import models -class TestBase(AsyncHTTPTestCase): +class TestBase(testing.AsyncHTTPTestCase): headers = {'Content-Type': 'application/json; charset=UTF-8'} def setUp(self): + self._patch_server() self.basePath = '' - self.create_res = CreateResponse + self.create_res = models.CreateResponse self.get_res = None self.list_res = None self.update_res = None @@ -30,12 +32,24 @@ class TestBase(AsyncHTTPTestCase): self.addCleanup(self._clear) super(TestBase, self).setUp() + def tearDown(self): + self.db_patcher.stop() + + def _patch_server(self): + server.parse_config([ + '--config-file', + path.join(path.dirname(__file__), 'common/normal.ini') + ]) + self.db_patcher = mock.patch('opnfv_testapi.cmd.server.get_db', + self._fake_pymongo) + self.db_patcher.start() + + @staticmethod + def _fake_pymongo(): + return fake_pymongo + def get_app(self): - return Application( - url_mappings.mappings, - db=fake_pymongo, - debug=True, - ) + return server.make_app() def create_d(self, *args): return self.create(self.req_d, *args) diff --git a/utils/test/testapi/opnfv_testapi/tests/unit/test_fake_pymongo.py b/utils/test/testapi/opnfv_testapi/tests/unit/test_fake_pymongo.py index 5f50ba867..7c43fca62 100644 --- a/utils/test/testapi/opnfv_testapi/tests/unit/test_fake_pymongo.py +++ b/utils/test/testapi/opnfv_testapi/tests/unit/test_fake_pymongo.py @@ -9,13 +9,13 @@ import unittest from tornado import gen -from tornado.testing import AsyncHTTPTestCase, gen_test -from tornado.web import Application +from tornado import testing +from tornado import web import fake_pymongo -class MyTest(AsyncHTTPTestCase): +class MyTest(testing.AsyncHTTPTestCase): def setUp(self): super(MyTest, self).setUp() self.db = fake_pymongo @@ -23,7 +23,7 @@ class MyTest(AsyncHTTPTestCase): self.io_loop.run_sync(self.fixture_setup) def get_app(self): - return Application() + return web.Application() @gen.coroutine def fixture_setup(self): @@ -32,13 +32,13 @@ class MyTest(AsyncHTTPTestCase): yield self.db.pods.insert({'_id': '1', 'name': 'test1'}) yield self.db.pods.insert({'name': 'test2'}) - @gen_test + @testing.gen_test def test_find_one(self): user = yield self.db.pods.find_one({'name': 'test1'}) self.assertEqual(user, self.test1) self.db.pods.remove() - @gen_test + @testing.gen_test def test_find(self): cursor = self.db.pods.find() names = [] @@ -47,7 +47,7 @@ class MyTest(AsyncHTTPTestCase): names.append(ob.get('name')) self.assertItemsEqual(names, ['test1', 'test2']) - @gen_test + @testing.gen_test def test_update(self): yield self.db.pods.update({'_id': '1'}, {'name': 'new_test1'}) user = yield self.db.pods.find_one({'_id': '1'}) @@ -71,7 +71,7 @@ class MyTest(AsyncHTTPTestCase): None, check_keys=False) - @gen_test + @testing.gen_test def test_remove(self): yield self.db.pods.remove({'_id': '1'}) user = yield self.db.pods.find_one({'_id': '1'}) @@ -104,7 +104,7 @@ class MyTest(AsyncHTTPTestCase): def _insert_assert(self, docs, error=None, **kwargs): self._db_assert('insert', error, docs, **kwargs) - @gen_test + @testing.gen_test def _db_assert(self, method, error, *args, **kwargs): name_error = None try: diff --git a/utils/test/testapi/opnfv_testapi/tests/unit/test_pod.py b/utils/test/testapi/opnfv_testapi/tests/unit/test_pod.py index a1184d554..922bd46e2 100644 --- a/utils/test/testapi/opnfv_testapi/tests/unit/test_pod.py +++ b/utils/test/testapi/opnfv_testapi/tests/unit/test_pod.py @@ -8,20 +8,19 @@ ############################################################################## import unittest -from test_base import TestBase -from opnfv_testapi.resources.pod_models import PodCreateRequest, Pod, Pods -from opnfv_testapi.common.constants import HTTP_OK, HTTP_BAD_REQUEST, \ - HTTP_FORBIDDEN, HTTP_NOT_FOUND +from opnfv_testapi.common import constants +from opnfv_testapi.resources import pod_models +import test_base as base -class TestPodBase(TestBase): +class TestPodBase(base.TestBase): def setUp(self): super(TestPodBase, self).setUp() - self.req_d = PodCreateRequest('zte-1', 'virtual', - 'zte pod 1', 'ci-pod') - self.req_e = PodCreateRequest('zte-2', 'metal', 'zte pod 2') - self.get_res = Pod - self.list_res = Pods + self.req_d = pod_models.PodCreateRequest('zte-1', 'virtual', + 'zte pod 1', 'ci-pod') + self.req_e = pod_models.PodCreateRequest('zte-2', 'metal', 'zte pod 2') + self.get_res = pod_models.Pod + self.list_res = pod_models.Pods self.basePath = '/api/v1/pods' def assert_get_body(self, pod, req=None): @@ -38,36 +37,36 @@ class TestPodBase(TestBase): class TestPodCreate(TestPodBase): def test_withoutBody(self): (code, body) = self.create() - self.assertEqual(code, HTTP_BAD_REQUEST) + self.assertEqual(code, constants.HTTP_BAD_REQUEST) def test_emptyName(self): - req_empty = PodCreateRequest('') + req_empty = pod_models.PodCreateRequest('') (code, body) = self.create(req_empty) - self.assertEqual(code, HTTP_BAD_REQUEST) + self.assertEqual(code, constants.HTTP_BAD_REQUEST) self.assertIn('name missing', body) def test_noneName(self): - req_none = PodCreateRequest(None) + req_none = pod_models.PodCreateRequest(None) (code, body) = self.create(req_none) - self.assertEqual(code, HTTP_BAD_REQUEST) + self.assertEqual(code, constants.HTTP_BAD_REQUEST) self.assertIn('name missing', body) def test_success(self): code, body = self.create_d() - self.assertEqual(code, HTTP_OK) + self.assertEqual(code, constants.HTTP_OK) self.assert_create_body(body) def test_alreadyExist(self): self.create_d() code, body = self.create_d() - self.assertEqual(code, HTTP_FORBIDDEN) + self.assertEqual(code, constants.HTTP_FORBIDDEN) self.assertIn('already exists', body) class TestPodGet(TestPodBase): def test_notExist(self): code, body = self.get('notExist') - self.assertEqual(code, HTTP_NOT_FOUND) + self.assertEqual(code, constants.HTTP_NOT_FOUND) def test_getOne(self): self.create_d() diff --git a/utils/test/testapi/opnfv_testapi/tests/unit/test_project.py b/utils/test/testapi/opnfv_testapi/tests/unit/test_project.py index 327ddf7b2..afd4a6601 100644 --- a/utils/test/testapi/opnfv_testapi/tests/unit/test_project.py +++ b/utils/test/testapi/opnfv_testapi/tests/unit/test_project.py @@ -8,21 +8,21 @@ ############################################################################## import unittest -from test_base import TestBase -from opnfv_testapi.resources.project_models import ProjectCreateRequest, \ - Project, Projects, ProjectUpdateRequest -from opnfv_testapi.common.constants import HTTP_OK, HTTP_BAD_REQUEST, \ - HTTP_FORBIDDEN, HTTP_NOT_FOUND +from opnfv_testapi.common import constants +from opnfv_testapi.resources import project_models +import test_base as base -class TestProjectBase(TestBase): +class TestProjectBase(base.TestBase): def setUp(self): super(TestProjectBase, self).setUp() - self.req_d = ProjectCreateRequest('vping', 'vping-ssh test') - self.req_e = ProjectCreateRequest('doctor', 'doctor test') - self.get_res = Project - self.list_res = Projects - self.update_res = Project + self.req_d = project_models.ProjectCreateRequest('vping', + 'vping-ssh test') + self.req_e = project_models.ProjectCreateRequest('doctor', + 'doctor test') + self.get_res = project_models.Project + self.list_res = project_models.Projects + self.update_res = project_models.Project self.basePath = '/api/v1/projects' def assert_body(self, project, req=None): @@ -37,41 +37,41 @@ class TestProjectBase(TestBase): class TestProjectCreate(TestProjectBase): def test_withoutBody(self): (code, body) = self.create() - self.assertEqual(code, HTTP_BAD_REQUEST) + self.assertEqual(code, constants.HTTP_BAD_REQUEST) def test_emptyName(self): - req_empty = ProjectCreateRequest('') + req_empty = project_models.ProjectCreateRequest('') (code, body) = self.create(req_empty) - self.assertEqual(code, HTTP_BAD_REQUEST) + self.assertEqual(code, constants.HTTP_BAD_REQUEST) self.assertIn('name missing', body) def test_noneName(self): - req_none = ProjectCreateRequest(None) + req_none = project_models.ProjectCreateRequest(None) (code, body) = self.create(req_none) - self.assertEqual(code, HTTP_BAD_REQUEST) + self.assertEqual(code, constants.HTTP_BAD_REQUEST) self.assertIn('name missing', body) def test_success(self): (code, body) = self.create_d() - self.assertEqual(code, HTTP_OK) + self.assertEqual(code, constants.HTTP_OK) self.assert_create_body(body) def test_alreadyExist(self): self.create_d() (code, body) = self.create_d() - self.assertEqual(code, HTTP_FORBIDDEN) + self.assertEqual(code, constants.HTTP_FORBIDDEN) self.assertIn('already exists', body) class TestProjectGet(TestProjectBase): def test_notExist(self): code, body = self.get('notExist') - self.assertEqual(code, HTTP_NOT_FOUND) + self.assertEqual(code, constants.HTTP_NOT_FOUND) def test_getOne(self): self.create_d() code, body = self.get(self.req_d.name) - self.assertEqual(code, HTTP_OK) + self.assertEqual(code, constants.HTTP_OK) self.assert_body(body) def test_list(self): @@ -88,23 +88,23 @@ class TestProjectGet(TestProjectBase): class TestProjectUpdate(TestProjectBase): def test_withoutBody(self): code, _ = self.update(None, 'noBody') - self.assertEqual(code, HTTP_BAD_REQUEST) + self.assertEqual(code, constants.HTTP_BAD_REQUEST) def test_notFound(self): code, _ = self.update(self.req_e, 'notFound') - self.assertEqual(code, HTTP_NOT_FOUND) + self.assertEqual(code, constants.HTTP_NOT_FOUND) def test_newNameExist(self): self.create_d() self.create_e() code, body = self.update(self.req_e, self.req_d.name) - self.assertEqual(code, HTTP_FORBIDDEN) + self.assertEqual(code, constants.HTTP_FORBIDDEN) self.assertIn("already exists", body) def test_noUpdate(self): self.create_d() code, body = self.update(self.req_d, self.req_d.name) - self.assertEqual(code, HTTP_FORBIDDEN) + self.assertEqual(code, constants.HTTP_FORBIDDEN) self.assertIn("Nothing to update", body) def test_success(self): @@ -112,9 +112,9 @@ class TestProjectUpdate(TestProjectBase): code, body = self.get(self.req_d.name) _id = body._id - req = ProjectUpdateRequest('newName', 'new description') + req = project_models.ProjectUpdateRequest('newName', 'new description') code, body = self.update(req, self.req_d.name) - self.assertEqual(code, HTTP_OK) + self.assertEqual(code, constants.HTTP_OK) self.assertEqual(_id, body._id) self.assert_body(body, req) @@ -126,16 +126,16 @@ class TestProjectUpdate(TestProjectBase): class TestProjectDelete(TestProjectBase): def test_notFound(self): code, body = self.delete('notFound') - self.assertEqual(code, HTTP_NOT_FOUND) + self.assertEqual(code, constants.HTTP_NOT_FOUND) def test_success(self): self.create_d() code, body = self.delete(self.req_d.name) - self.assertEqual(code, HTTP_OK) + self.assertEqual(code, constants.HTTP_OK) self.assertEqual(body, '') code, body = self.get(self.req_d.name) - self.assertEqual(code, HTTP_NOT_FOUND) + self.assertEqual(code, constants.HTTP_NOT_FOUND) if __name__ == '__main__': unittest.main() diff --git a/utils/test/testapi/opnfv_testapi/tests/unit/test_result.py b/utils/test/testapi/opnfv_testapi/tests/unit/test_result.py index 10575a9f5..2c7268eb6 100644 --- a/utils/test/testapi/opnfv_testapi/tests/unit/test_result.py +++ b/utils/test/testapi/opnfv_testapi/tests/unit/test_result.py @@ -7,17 +7,15 @@ # http://www.apache.org/licenses/LICENSE-2.0 ############################################################################## import copy -import unittest from datetime import datetime, timedelta +import unittest -from opnfv_testapi.common.constants import HTTP_OK, HTTP_BAD_REQUEST, \ - HTTP_NOT_FOUND -from opnfv_testapi.resources.pod_models import PodCreateRequest -from opnfv_testapi.resources.project_models import ProjectCreateRequest -from opnfv_testapi.resources.result_models import ResultCreateRequest, \ - TestResult, TestResults, ResultUpdateRequest, TI, TIHistory -from opnfv_testapi.resources.testcase_models import TestcaseCreateRequest -from test_base import TestBase +from opnfv_testapi.common import constants +from opnfv_testapi.resources import pod_models +from opnfv_testapi.resources import project_models +from opnfv_testapi.resources import result_models +from opnfv_testapi.resources import testcase_models +import test_base as base class Details(object): @@ -49,7 +47,7 @@ class Details(object): return t -class TestResultBase(TestBase): +class TestResultBase(base.TestBase): def setUp(self): self.pod = 'zte-pod1' self.project = 'functest' @@ -59,34 +57,41 @@ class TestResultBase(TestBase): self.build_tag = 'v3.0' self.scenario = 'odl-l2' self.criteria = 'passed' - self.trust_indicator = TI(0.7) + self.trust_indicator = result_models.TI(0.7) self.start_date = "2016-05-23 07:16:09.477097" self.stop_date = "2016-05-23 07:16:19.477097" self.update_date = "2016-05-24 07:16:19.477097" self.update_step = -0.05 super(TestResultBase, self).setUp() self.details = Details(timestart='0', duration='9s', status='OK') - self.req_d = ResultCreateRequest(pod_name=self.pod, - project_name=self.project, - case_name=self.case, - installer=self.installer, - version=self.version, - start_date=self.start_date, - stop_date=self.stop_date, - details=self.details.format(), - build_tag=self.build_tag, - scenario=self.scenario, - criteria=self.criteria, - trust_indicator=self.trust_indicator) - self.get_res = TestResult - self.list_res = TestResults - self.update_res = TestResult + self.req_d = result_models.ResultCreateRequest( + pod_name=self.pod, + project_name=self.project, + case_name=self.case, + installer=self.installer, + version=self.version, + start_date=self.start_date, + stop_date=self.stop_date, + details=self.details.format(), + build_tag=self.build_tag, + scenario=self.scenario, + criteria=self.criteria, + trust_indicator=self.trust_indicator) + self.get_res = result_models.TestResult + self.list_res = result_models.TestResults + self.update_res = result_models.TestResult self.basePath = '/api/v1/results' - self.req_pod = PodCreateRequest(self.pod, 'metal', 'zte pod 1') - self.req_project = ProjectCreateRequest(self.project, 'vping test') - self.req_testcase = TestcaseCreateRequest(self.case, - '/cases/vping', - 'vping-ssh test') + self.req_pod = pod_models.PodCreateRequest( + self.pod, + 'metal', + 'zte pod 1') + self.req_project = project_models.ProjectCreateRequest( + self.project, + 'vping test') + self.req_testcase = testcase_models.TestcaseCreateRequest( + self.case, + '/cases/vping', + 'vping-ssh test') self.create_help('/api/v1/pods', self.req_pod) self.create_help('/api/v1/projects', self.req_project) self.create_help('/api/v1/projects/%s/cases', @@ -94,7 +99,7 @@ class TestResultBase(TestBase): self.project) def assert_res(self, code, result, req=None): - self.assertEqual(code, HTTP_OK) + self.assertEqual(code, constants.HTTP_OK) if req is None: req = self.req_d self.assertEqual(result.pod_name, req.pod_name) @@ -129,78 +134,78 @@ class TestResultBase(TestBase): class TestResultCreate(TestResultBase): def test_nobody(self): (code, body) = self.create(None) - self.assertEqual(code, HTTP_BAD_REQUEST) + self.assertEqual(code, constants.HTTP_BAD_REQUEST) self.assertIn('no body', body) def test_podNotProvided(self): req = self.req_d req.pod_name = None (code, body) = self.create(req) - self.assertEqual(code, HTTP_BAD_REQUEST) + self.assertEqual(code, constants.HTTP_BAD_REQUEST) self.assertIn('pod_name missing', body) def test_projectNotProvided(self): req = self.req_d req.project_name = None (code, body) = self.create(req) - self.assertEqual(code, HTTP_BAD_REQUEST) + self.assertEqual(code, constants.HTTP_BAD_REQUEST) self.assertIn('project_name missing', body) def test_testcaseNotProvided(self): req = self.req_d req.case_name = None (code, body) = self.create(req) - self.assertEqual(code, HTTP_BAD_REQUEST) + self.assertEqual(code, constants.HTTP_BAD_REQUEST) self.assertIn('case_name missing', body) def test_noPod(self): req = self.req_d req.pod_name = 'notExistPod' (code, body) = self.create(req) - self.assertEqual(code, HTTP_NOT_FOUND) + self.assertEqual(code, constants.HTTP_NOT_FOUND) self.assertIn('Could not find pod', body) def test_noProject(self): req = self.req_d req.project_name = 'notExistProject' (code, body) = self.create(req) - self.assertEqual(code, HTTP_NOT_FOUND) + self.assertEqual(code, constants.HTTP_NOT_FOUND) self.assertIn('Could not find project', body) def test_noTestcase(self): req = self.req_d req.case_name = 'notExistTestcase' (code, body) = self.create(req) - self.assertEqual(code, HTTP_NOT_FOUND) + self.assertEqual(code, constants.HTTP_NOT_FOUND) self.assertIn('Could not find testcase', body) def test_success(self): (code, body) = self.create_d() - self.assertEqual(code, HTTP_OK) + self.assertEqual(code, constants.HTTP_OK) self.assert_href(body) def test_key_with_doc(self): req = copy.deepcopy(self.req_d) req.details = {'1.name': 'dot_name'} (code, body) = self.create(req) - self.assertEqual(code, HTTP_OK) + self.assertEqual(code, constants.HTTP_OK) self.assert_href(body) def test_no_ti(self): - req = ResultCreateRequest(pod_name=self.pod, - project_name=self.project, - case_name=self.case, - installer=self.installer, - version=self.version, - start_date=self.start_date, - stop_date=self.stop_date, - details=self.details.format(), - build_tag=self.build_tag, - scenario=self.scenario, - criteria=self.criteria) + req = result_models.ResultCreateRequest(pod_name=self.pod, + project_name=self.project, + case_name=self.case, + installer=self.installer, + version=self.version, + start_date=self.start_date, + stop_date=self.stop_date, + details=self.details.format(), + build_tag=self.build_tag, + scenario=self.scenario, + criteria=self.criteria) (code, res) = self.create(req) _id = res.href.split('/')[-1] - self.assertEqual(code, HTTP_OK) + self.assertEqual(code, constants.HTTP_OK) code, body = self.get(_id) self.assert_res(code, body, req) @@ -240,7 +245,7 @@ class TestResultGet(TestResultBase): def test_queryPeriodNotInt(self): code, body = self.query(self._set_query('period=a')) - self.assertEqual(code, HTTP_BAD_REQUEST) + self.assertEqual(code, constants.HTTP_BAD_REQUEST) self.assertIn('period must be int', body) def test_queryPeriodFail(self): @@ -253,7 +258,7 @@ class TestResultGet(TestResultBase): def test_queryLastNotInt(self): code, body = self.query(self._set_query('last=a')) - self.assertEqual(code, HTTP_BAD_REQUEST) + self.assertEqual(code, constants.HTTP_BAD_REQUEST) self.assertIn('last must be int', body) def test_queryLast(self): @@ -292,7 +297,7 @@ class TestResultGet(TestResultBase): req = self._create_changed_date(**kwargs) code, body = self.query(query) if not found: - self.assertEqual(code, HTTP_OK) + self.assertEqual(code, constants.HTTP_OK) self.assertEqual(0, len(body.results)) else: self.assertEqual(1, len(body.results)) @@ -326,10 +331,11 @@ class TestResultUpdate(TestResultBase): new_ti = copy.deepcopy(self.trust_indicator) new_ti.current += self.update_step - new_ti.histories.append(TIHistory(self.update_date, self.update_step)) + new_ti.histories.append( + result_models.TIHistory(self.update_date, self.update_step)) new_data = copy.deepcopy(self.req_d) new_data.trust_indicator = new_ti - update = ResultUpdateRequest(trust_indicator=new_ti) + update = result_models.ResultUpdateRequest(trust_indicator=new_ti) code, body = self.update(update, _id) self.assertEqual(_id, body._id) self.assert_res(code, body, new_data) diff --git a/utils/test/testapi/opnfv_testapi/tests/unit/test_scenario.py b/utils/test/testapi/opnfv_testapi/tests/unit/test_scenario.py index c15dc32ea..7a6e94a93 100644 --- a/utils/test/testapi/opnfv_testapi/tests/unit/test_scenario.py +++ b/utils/test/testapi/opnfv_testapi/tests/unit/test_scenario.py @@ -1,16 +1,14 @@ from copy import deepcopy +from datetime import datetime import json import os -from datetime import datetime -from opnfv_testapi.common.constants import HTTP_BAD_REQUEST -from opnfv_testapi.common.constants import HTTP_FORBIDDEN -from opnfv_testapi.common.constants import HTTP_OK +from opnfv_testapi.common import constants import opnfv_testapi.resources.scenario_models as models -from test_testcase import TestBase +import test_base as base -class TestScenarioBase(TestBase): +class TestScenarioBase(base.TestBase): def setUp(self): super(TestScenarioBase, self).setUp() self.get_res = models.Scenario @@ -38,13 +36,13 @@ class TestScenarioBase(TestBase): return res.href.split('/')[-1] def assert_res(self, code, scenario, req=None): - self.assertEqual(code, HTTP_OK) + self.assertEqual(code, constants.HTTP_OK) if req is None: req = self.req_d - scenario_dict = scenario.format_http() - self.assertIsNotNone(scenario_dict['_id']) - self.assertIsNotNone(scenario_dict['creation_date']) - self.assertDictContainsSubset(req, scenario_dict) + self.assertIsNotNone(scenario._id) + self.assertIsNotNone(scenario.creation_date) + + scenario == models.Scenario.from_dict(req) @staticmethod def _set_query(*args): @@ -61,29 +59,29 @@ class TestScenarioBase(TestBase): class TestScenarioCreate(TestScenarioBase): def test_withoutBody(self): (code, body) = self.create() - self.assertEqual(code, HTTP_BAD_REQUEST) + self.assertEqual(code, constants.HTTP_BAD_REQUEST) def test_emptyName(self): req_empty = models.ScenarioCreateRequest('') (code, body) = self.create(req_empty) - self.assertEqual(code, HTTP_BAD_REQUEST) + self.assertEqual(code, constants.HTTP_BAD_REQUEST) self.assertIn('name missing', body) def test_noneName(self): req_none = models.ScenarioCreateRequest(None) (code, body) = self.create(req_none) - self.assertEqual(code, HTTP_BAD_REQUEST) + self.assertEqual(code, constants.HTTP_BAD_REQUEST) self.assertIn('name missing', body) def test_success(self): (code, body) = self.create_d() - self.assertEqual(code, HTTP_OK) + self.assertEqual(code, constants.HTTP_OK) self.assert_create_body(body) def test_alreadyExist(self): self.create_d() (code, body) = self.create_d() - self.assertEqual(code, HTTP_FORBIDDEN) + self.assertEqual(code, constants.HTTP_FORBIDDEN) self.assertIn('already exists', body) @@ -126,7 +124,7 @@ class TestScenarioGet(TestScenarioBase): def _query_and_assert(self, query, found=True, reqs=None): code, body = self.query(query) if not found: - self.assertEqual(code, HTTP_OK) + self.assertEqual(code, constants.HTTP_OK) self.assertEqual(0, len(body.scenarios)) else: self.assertEqual(len(reqs), len(body.scenarios)) @@ -296,10 +294,23 @@ class TestScenarioUpdate(TestScenarioBase): def _update_and_assert(self, update_req, new_scenario, name=None): code, _ = self.update(update_req, self.scenario) - self.assertEqual(code, HTTP_OK) + self.assertEqual(code, constants.HTTP_OK) self._get_and_assert(self._none_default(name, self.scenario), new_scenario) @staticmethod def _none_default(check, default): return check if check else default + + +class TestScenarioDelete(TestScenarioBase): + def test_notFound(self): + code, body = self.delete('notFound') + self.assertEqual(code, constants.HTTP_NOT_FOUND) + + def test_success(self): + scenario = self.create_return_name(self.req_d) + code, _ = self.delete(scenario) + self.assertEqual(code, constants.HTTP_OK) + code, _ = self.get(scenario) + self.assertEqual(code, constants.HTTP_NOT_FOUND) diff --git a/utils/test/testapi/opnfv_testapi/tests/unit/test_testcase.py b/utils/test/testapi/opnfv_testapi/tests/unit/test_testcase.py index cb767844a..c0494db5d 100644 --- a/utils/test/testapi/opnfv_testapi/tests/unit/test_testcase.py +++ b/utils/test/testapi/opnfv_testapi/tests/unit/test_testcase.py @@ -6,35 +6,33 @@ # which accompanies this distribution, and is available at # http://www.apache.org/licenses/LICENSE-2.0 ############################################################################## -import unittest import copy +import unittest -from test_base import TestBase -from opnfv_testapi.resources.testcase_models import TestcaseCreateRequest, \ - Testcase, Testcases, TestcaseUpdateRequest -from opnfv_testapi.resources.project_models import ProjectCreateRequest -from opnfv_testapi.common.constants import HTTP_OK, HTTP_BAD_REQUEST, \ - HTTP_FORBIDDEN, HTTP_NOT_FOUND +from opnfv_testapi.common import constants +from opnfv_testapi.resources import project_models +from opnfv_testapi.resources import testcase_models +import test_base as base -class TestCaseBase(TestBase): +class TestCaseBase(base.TestBase): def setUp(self): super(TestCaseBase, self).setUp() - self.req_d = TestcaseCreateRequest('vping_1', - '/cases/vping_1', - 'vping-ssh test') - self.req_e = TestcaseCreateRequest('doctor_1', - '/cases/doctor_1', - 'create doctor') - self.update_d = TestcaseUpdateRequest('vping_1', - 'vping-ssh test', - 'functest') - self.update_e = TestcaseUpdateRequest('doctor_1', - 'create doctor', - 'functest') - self.get_res = Testcase - self.list_res = Testcases - self.update_res = Testcase + self.req_d = testcase_models.TestcaseCreateRequest('vping_1', + '/cases/vping_1', + 'vping-ssh test') + self.req_e = testcase_models.TestcaseCreateRequest('doctor_1', + '/cases/doctor_1', + 'create doctor') + self.update_d = testcase_models.TestcaseUpdateRequest('vping_1', + 'vping-ssh test', + 'functest') + self.update_e = testcase_models.TestcaseUpdateRequest('doctor_1', + 'create doctor', + 'functest') + self.get_res = testcase_models.Testcase + self.list_res = testcase_models.Testcases + self.update_res = testcase_models.Testcase self.basePath = '/api/v1/projects/%s/cases' self.create_project() @@ -57,7 +55,8 @@ class TestCaseBase(TestBase): self.assertIsNotNone(new.creation_date) def create_project(self): - req_p = ProjectCreateRequest('functest', 'vping-ssh test') + req_p = project_models.ProjectCreateRequest('functest', + 'vping-ssh test') self.create_help('/api/v1/projects', req_p) self.project = req_p.name @@ -80,46 +79,46 @@ class TestCaseBase(TestBase): class TestCaseCreate(TestCaseBase): def test_noBody(self): (code, body) = self.create(None, 'vping') - self.assertEqual(code, HTTP_BAD_REQUEST) + self.assertEqual(code, constants.HTTP_BAD_REQUEST) def test_noProject(self): code, body = self.create(self.req_d, 'noProject') - self.assertEqual(code, HTTP_FORBIDDEN) + self.assertEqual(code, constants.HTTP_FORBIDDEN) self.assertIn('Could not find project', body) def test_emptyName(self): - req_empty = TestcaseCreateRequest('') + req_empty = testcase_models.TestcaseCreateRequest('') (code, body) = self.create(req_empty, self.project) - self.assertEqual(code, HTTP_BAD_REQUEST) + self.assertEqual(code, constants.HTTP_BAD_REQUEST) self.assertIn('name missing', body) def test_noneName(self): - req_none = TestcaseCreateRequest(None) + req_none = testcase_models.TestcaseCreateRequest(None) (code, body) = self.create(req_none, self.project) - self.assertEqual(code, HTTP_BAD_REQUEST) + self.assertEqual(code, constants.HTTP_BAD_REQUEST) self.assertIn('name missing', body) def test_success(self): code, body = self.create_d() - self.assertEqual(code, HTTP_OK) + self.assertEqual(code, constants.HTTP_OK) self.assert_create_body(body, None, self.project) def test_alreadyExist(self): self.create_d() code, body = self.create_d() - self.assertEqual(code, HTTP_FORBIDDEN) + self.assertEqual(code, constants.HTTP_FORBIDDEN) self.assertIn('already exists', body) class TestCaseGet(TestCaseBase): def test_notExist(self): code, body = self.get('notExist') - self.assertEqual(code, HTTP_NOT_FOUND) + self.assertEqual(code, constants.HTTP_NOT_FOUND) def test_getOne(self): self.create_d() code, body = self.get(self.req_d.name) - self.assertEqual(code, HTTP_OK) + self.assertEqual(code, constants.HTTP_OK) self.assert_body(body) def test_list(self): @@ -136,23 +135,23 @@ class TestCaseGet(TestCaseBase): class TestCaseUpdate(TestCaseBase): def test_noBody(self): code, _ = self.update(case='noBody') - self.assertEqual(code, HTTP_BAD_REQUEST) + self.assertEqual(code, constants.HTTP_BAD_REQUEST) def test_notFound(self): code, _ = self.update(self.update_e, 'notFound') - self.assertEqual(code, HTTP_NOT_FOUND) + self.assertEqual(code, constants.HTTP_NOT_FOUND) def test_newNameExist(self): self.create_d() self.create_e() code, body = self.update(self.update_e, self.req_d.name) - self.assertEqual(code, HTTP_FORBIDDEN) + self.assertEqual(code, constants.HTTP_FORBIDDEN) self.assertIn("already exists", body) def test_noUpdate(self): self.create_d() code, body = self.update(self.update_d, self.req_d.name) - self.assertEqual(code, HTTP_FORBIDDEN) + self.assertEqual(code, constants.HTTP_FORBIDDEN) self.assertIn("Nothing to update", body) def test_success(self): @@ -161,7 +160,7 @@ class TestCaseUpdate(TestCaseBase): _id = body._id code, body = self.update(self.update_e, self.req_d.name) - self.assertEqual(code, HTTP_OK) + self.assertEqual(code, constants.HTTP_OK) self.assertEqual(_id, body._id) self.assert_update_body(self.req_d, body, self.update_e) @@ -174,22 +173,22 @@ class TestCaseUpdate(TestCaseBase): update = copy.deepcopy(self.update_d) update.description = {'2. change': 'dollar change'} code, body = self.update(update, self.req_d.name) - self.assertEqual(code, HTTP_OK) + self.assertEqual(code, constants.HTTP_OK) class TestCaseDelete(TestCaseBase): def test_notFound(self): code, body = self.delete('notFound') - self.assertEqual(code, HTTP_NOT_FOUND) + self.assertEqual(code, constants.HTTP_NOT_FOUND) def test_success(self): self.create_d() code, body = self.delete(self.req_d.name) - self.assertEqual(code, HTTP_OK) + self.assertEqual(code, constants.HTTP_OK) self.assertEqual(body, '') code, body = self.get(self.req_d.name) - self.assertEqual(code, HTTP_NOT_FOUND) + self.assertEqual(code, constants.HTTP_NOT_FOUND) if __name__ == '__main__': diff --git a/utils/test/testapi/opnfv_testapi/tests/unit/test_token.py b/utils/test/testapi/opnfv_testapi/tests/unit/test_token.py new file mode 100644 index 000000000..19b9e3e07 --- /dev/null +++ b/utils/test/testapi/opnfv_testapi/tests/unit/test_token.py @@ -0,0 +1,118 @@ +# All rights reserved. This program and the accompanying materials +# are made available under the terms of the Apache License, Version 2.0 +# which accompanies this distribution, and is available at +# http://www.apache.org/licenses/LICENSE-2.0 + +import unittest + +from tornado import web + +import fake_pymongo +from opnfv_testapi.common import constants +from opnfv_testapi.resources import project_models +from opnfv_testapi.router import url_mappings +import test_base as base + + +class TestToken(base.TestBase): + def get_app(self): + return web.Application( + url_mappings.mappings, + db=fake_pymongo, + debug=True, + auth=True + ) + + +class TestTokenCreateProject(TestToken): + def setUp(self): + super(TestTokenCreateProject, self).setUp() + self.req_d = project_models.ProjectCreateRequest('vping') + fake_pymongo.tokens.insert({"access_token": "12345"}) + self.basePath = '/api/v1/projects' + + def test_projectCreateTokenInvalid(self): + self.headers['X-Auth-Token'] = '1234' + code, body = self.create_d() + self.assertEqual(code, constants.HTTP_FORBIDDEN) + self.assertIn('Invalid Token.', body) + + def test_projectCreateTokenUnauthorized(self): + self.headers.pop('X-Auth-Token') + code, body = self.create_d() + self.assertEqual(code, constants.HTTP_UNAUTHORIZED) + self.assertIn('No Authentication Header.', body) + + def test_projectCreateTokenSuccess(self): + self.headers['X-Auth-Token'] = '12345' + code, body = self.create_d() + self.assertEqual(code, constants.HTTP_OK) + + +class TestTokenDeleteProject(TestToken): + def setUp(self): + super(TestTokenDeleteProject, self).setUp() + self.req_d = project_models.ProjectCreateRequest('vping') + fake_pymongo.tokens.insert({"access_token": "12345"}) + self.basePath = '/api/v1/projects' + + def test_projectDeleteTokenIvalid(self): + self.headers['X-Auth-Token'] = '12345' + self.create_d() + self.headers['X-Auth-Token'] = '1234' + code, body = self.delete(self.req_d.name) + self.assertEqual(code, constants.HTTP_FORBIDDEN) + self.assertIn('Invalid Token.', body) + + def test_projectDeleteTokenUnauthorized(self): + self.headers['X-Auth-Token'] = '12345' + self.create_d() + self.headers.pop('X-Auth-Token') + code, body = self.delete(self.req_d.name) + self.assertEqual(code, constants.HTTP_UNAUTHORIZED) + self.assertIn('No Authentication Header.', body) + + def test_projectDeleteTokenSuccess(self): + self.headers['X-Auth-Token'] = '12345' + self.create_d() + code, body = self.delete(self.req_d.name) + self.assertEqual(code, constants.HTTP_OK) + + +class TestTokenUpdateProject(TestToken): + def setUp(self): + super(TestTokenUpdateProject, self).setUp() + self.req_d = project_models.ProjectCreateRequest('vping') + fake_pymongo.tokens.insert({"access_token": "12345"}) + self.basePath = '/api/v1/projects' + + def test_projectUpdateTokenIvalid(self): + self.headers['X-Auth-Token'] = '12345' + self.create_d() + code, body = self.get(self.req_d.name) + self.headers['X-Auth-Token'] = '1234' + req = project_models.ProjectUpdateRequest('newName', 'new description') + code, body = self.update(req, self.req_d.name) + self.assertEqual(code, constants.HTTP_FORBIDDEN) + self.assertIn('Invalid Token.', body) + + def test_projectUpdateTokenUnauthorized(self): + self.headers['X-Auth-Token'] = '12345' + self.create_d() + code, body = self.get(self.req_d.name) + self.headers.pop('X-Auth-Token') + req = project_models.ProjectUpdateRequest('newName', 'new description') + code, body = self.update(req, self.req_d.name) + self.assertEqual(code, constants.HTTP_UNAUTHORIZED) + self.assertIn('No Authentication Header.', body) + + def test_projectUpdateTokenSuccess(self): + self.headers['X-Auth-Token'] = '12345' + self.create_d() + code, body = self.get(self.req_d.name) + req = project_models.ProjectUpdateRequest('newName', 'new description') + code, body = self.update(req, self.req_d.name) + self.assertEqual(code, constants.HTTP_OK) + +if __name__ == '__main__': + unittest.main() diff --git a/utils/test/testapi/opnfv_testapi/tests/unit/test_version.py b/utils/test/testapi/opnfv_testapi/tests/unit/test_version.py index b6fbf45dc..c8f3f5062 100644 --- a/utils/test/testapi/opnfv_testapi/tests/unit/test_version.py +++ b/utils/test/testapi/opnfv_testapi/tests/unit/test_version.py @@ -8,14 +8,14 @@ ############################################################################## import unittest -from test_base import TestBase -from opnfv_testapi.resources.models import Versions +from opnfv_testapi.resources import models +import test_base as base -class TestVersionBase(TestBase): +class TestVersionBase(base.TestBase): def setUp(self): super(TestVersionBase, self).setUp() - self.list_res = Versions + self.list_res = models.Versions self.basePath = '/versions' diff --git a/utils/test/testapi/run_test.sh b/utils/test/testapi/run_test.sh index 51db09f65..4efc7af3b 100755 --- a/utils/test/testapi/run_test.sh +++ b/utils/test/testapi/run_test.sh @@ -15,6 +15,8 @@ source $SCRIPTDIR/testapi_venv/bin/activate pip install -r $SCRIPTDIR/requirements.txt pip install coverage pip install nose>=1.3.1 +pip install pytest +pip install mock find . -type f -name "*.pyc" -delete diff --git a/utils/test/testapi/test-requirements.txt b/utils/test/testapi/test-requirements.txt new file mode 100644 index 000000000..4633ad637 --- /dev/null +++ b/utils/test/testapi/test-requirements.txt @@ -0,0 +1,11 @@ +# The order of packages is significant, because pip processes them in the order +# of appearance. Changing the order has an impact on the overall integration +# process, which may cause wedges in the gate later. + +tox +mock +pytest +pytest-cov +coverage +pykwalify +pip_check_reqs diff --git a/utils/test/testapi/tox.ini b/utils/test/testapi/tox.ini new file mode 100644 index 000000000..81c9dfab1 --- /dev/null +++ b/utils/test/testapi/tox.ini @@ -0,0 +1,41 @@ +# Tox (http://tox.testrun.org/) is a tool for running tests +# in multiple virtualenvs. This configuration file will run the +# test suite on all supported python versions. To use it, "pip install tox" +# and then run "tox" from this directory. + +[tox] +envlist = py27,pep8 +skipsdist = True +sitepackages = True + +[testenv] +usedevelop = True +install_command = pip install -U {opts} {packages} +deps = + -rrequirements.txt + -rtest-requirements.txt +commands= + py.test \ + --basetemp={envtmpdir} \ + --cov \ + {posargs} +setenv= + HOME = {envtmpdir} + PYTHONPATH = {toxinidir} + +[testenv:pep8] +deps = flake8 +commands = flake8 {toxinidir} + +[flake8] +# H803 skipped on purpose per list discussion. +# E123, E125 skipped as they are invalid PEP-8. + +show-source = True +ignore = E123,E125,H803,E501 +builtins = _ +exclude = build,dist,doc,legacy,.eggs,.git,.tox,.venv,testapi_venv,venv + +[pytest] +testpaths = opnfv_testapi/tests +python_functions = test_* diff --git a/utils/test/testapi/update/test.yml b/utils/test/testapi/update/test.yml index a8868720d..943105c5f 100644 --- a/utils/test/testapi/update/test.yml +++ b/utils/test/testapi/update/test.yml @@ -1,7 +1,7 @@ --- - hosts: "{{ host }}" remote_user: "{{ user }}" - become: yes + become: "yes" become_method: sudo vars: user: "root" diff --git a/utils/test/testapi/update/update.yml b/utils/test/testapi/update/update.yml index e6663d905..18b75b6bf 100644 --- a/utils/test/testapi/update/update.yml +++ b/utils/test/testapi/update/update.yml @@ -1,7 +1,7 @@ --- - hosts: "{{ host }}" remote_user: "{{ user }}" - become: yes + become: "yes" become_method: sudo vars: user: "root" @@ -47,4 +47,4 @@ - name: remove temporary update directory file: path: "{{ update_path }}" - state: absent
\ No newline at end of file + state: absent diff --git a/utils/test/vnfcatalogue/helpers/migrate.js b/utils/test/vnfcatalogue/helpers/migrate.js index a26f6ef88..d884d9c68 100644 --- a/utils/test/vnfcatalogue/helpers/migrate.js +++ b/utils/test/vnfcatalogue/helpers/migrate.js @@ -28,6 +28,14 @@ function createTable(tableName) { if (Schema[tableName][key].type === 'text' && Schema[tableName][key].hasOwnProperty('fieldtype')) { column = table[Schema[tableName][key].type](key, Schema[tableName][key].fieldtype); } + else if (Schema[tableName][key].type === 'enum' && Schema[tableName][key].hasOwnProperty('values') && Schema[tableName][key].nullable === true) { + console.log(Schema[tableName][key].values); + column = table[Schema[tableName][key].type](key, Schema[tableName][key].values).nullable(); + } + else if (Schema[tableName][key].type === 'enum' && Schema[tableName][key].hasOwnProperty('values')) { + console.log(Schema[tableName][key].values); + column = table[Schema[tableName][key].type](key, Schema[tableName][key].values).notNullable(); + } else if (Schema[tableName][key].type === 'string' && Schema[tableName][key].hasOwnProperty('maxlength')) { column = table[Schema[tableName][key].type](key, Schema[tableName][key].maxlength); } diff --git a/utils/test/vnfcatalogue/helpers/schema.js b/utils/test/vnfcatalogue/helpers/schema.js index 2aaf99ae2..4a7559ad0 100644 --- a/utils/test/vnfcatalogue/helpers/schema.js +++ b/utils/test/vnfcatalogue/helpers/schema.js @@ -31,10 +31,16 @@ var Schema = { lines_of_code: {type: 'integer', nullable: true, unsigned: true}, versions: {type: 'integer', nullable: true, unsigned: true}, no_of_developers: {type: 'integer', nullable: true, unsigned: true}, + no_of_stars: {type: 'integer', nullable: true, unsigned: true}, + license: {type: 'enum', nullable: false, values: ['MIT', 'GPL', 'GPL_V2', 'BSD', 'APACHE']}, + opnfv_indicator: {type: 'enum', nullable: false, values: ['gold', 'silver', 'platinum']}, + complexity: {type: 'enum', nullable: true, values: ['low', 'medium', 'high']}, + activity: {type: 'enum', nullable: true, values: ['low', 'medium', 'high']}, + last_updated: {type: 'dateTime', nullable: true}, }, tag: { tag_id: {type: 'increments', nullable: false, primary: true}, - name: {type: 'string', maxlength: 150, nullable: false} + tag_name: {type: 'string', maxlength: 150, nullable: false} }, vnf_tags: { vnf_tag_id: {type: 'increments', nullable: false, primary: true}, |