diff options
111 files changed, 7429 insertions, 3318 deletions
diff --git a/dashboard/README.rst b/dashboard/README.rst deleted file mode 100644 index e69de29..0000000 --- a/dashboard/README.rst +++ /dev/null diff --git a/dashboard/backup-db.sh b/dashboard/backup-db.sh deleted file mode 100644 index 35c3fbe..0000000 --- a/dashboard/backup-db.sh +++ /dev/null @@ -1,33 +0,0 @@ -#!/bin/bash -# SPDX-license-identifier: Apache-2.0 -############################################################################## -# Copyright (c) 2016 Orange and others. -# 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 -############################################################################## -echo "Backup Test collection DB" -now=$(date +"%m_%d_%Y_%H_%M_%S") -echo $now -echo " ------------- " -TARGET_DIR=./$now -TEST_RESULT_DB_BACKUP="test_collection_db."$now".tar.gz" - -echo "Create Directory for backup" -mkdir -p $TARGET_DIR - -echo "Export results" -mongoexport --db test_results_collection -c results --out $TARGET_DIR/backup-results.json -echo "Export test cases" -mongoexport --db test_results_collection -c testcases --out $TARGET_DIR/backup-cases.json -echo "Export projects" -mongoexport --db test_results_collection -c projects --out $TARGET_DIR/backup-projects.json -echo "Export pods" -mongoexport --db test_results_collection -c pods --out $TARGET_DIR/backup-pod.json - -echo "Create tar.gz" -#tar -cvzf $TEST_RESULT_DB_BACKUP $TARGET_DIR - -echo "Delete temp directory" -#rm -Rf $TARGET_DIR diff --git a/dashboard/dashboard/__init__.py b/dashboard/dashboard/__init__.py deleted file mode 100644 index e69de29..0000000 --- a/dashboard/dashboard/__init__.py +++ /dev/null diff --git a/dashboard/dashboard/common/__init__.py b/dashboard/dashboard/common/__init__.py deleted file mode 100644 index e69de29..0000000 --- a/dashboard/dashboard/common/__init__.py +++ /dev/null diff --git a/dashboard/dashboard/common/elastic_access.py b/dashboard/dashboard/common/elastic_access.py deleted file mode 100644 index eb29ce8..0000000 --- a/dashboard/dashboard/common/elastic_access.py +++ /dev/null @@ -1,51 +0,0 @@ -import json -import urlparse - -import urllib3 - -http = urllib3.PoolManager() - - -def _request(method, url, creds=None, body=None): - headers = urllib3.make_headers(basic_auth=creds) - return http.request(method, url, headers=headers, body=body) - - -def _post(url, creds=None, body=None): - return _request('POST', url, creds=creds, body=body) - - -def _get(url, creds=None, body=None): - return json.loads(_request('GET', url, creds=creds, body=body).data) - - -def delete_docs(url, creds=None, body=None): - return _request('DELETE', url, creds=creds, body=body) - - -def publish_docs(url, creds=None, body=None): - result = _post(url, creds=creds, body=(json.dumps(body))) - return result.status, result.data - - -def _get_docs_nr(url, creds=None, body=None): - res_data = _get('{}/_search?size=0'.format(url), creds=creds, body=body) - print(type(res_data), res_data) - return res_data['hits']['total'] - - -def get_docs(url, creds=None, body=None, field='_source'): - - docs_nr = _get_docs_nr(url, creds=creds, body=body) - res_data = _get('{}/_search?size={}'.format(url, docs_nr), - creds=creds, body=body) - - docs = [] - for hit in res_data['hits']['hits']: - docs.append(hit[field]) - return docs - - -def publish_kibana(url, creds, type, id, body): - url = urlparse.urljoin(url, '/.kibana/{}/{}'.format(type, id)) - publish_docs(url, creds, body) diff --git a/dashboard/dashboard/common/logger_utils.py b/dashboard/dashboard/common/logger_utils.py deleted file mode 100644 index 58e343d..0000000 --- a/dashboard/dashboard/common/logger_utils.py +++ /dev/null @@ -1,64 +0,0 @@ -#!/usr/bin/env python -# -# feng.xiaowei@zte.com.cn -# 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 -# -# Logging levels: -# Level Numeric value -# CRITICAL 50 -# ERROR 40 -# WARNING 30 -# INFO 20 -# DEBUG 10 -# NOTSET 0 -# -# Usage: -# import functest_logger as fl -# logger = fl.Logger("script_name").getLogger() -# logger.info("message to be shown with - INFO - ") -# logger.debug("message to be shown with - DEBUG -") - -import logging -import os - - -class Logger(object): - file_path = '/var/log' - formatter = logging.Formatter('%(asctime)s - %(name)s - ' - '%(levelname)s - %(message)s') - - def __init__(self, logger_name): - - IF_DEBUG = os.getenv('IF_DEBUG') - - self.logger_name = logger_name - self.logger = logging.getLogger(logger_name) - self.logger.propagate = 0 - self.logger.setLevel(logging.DEBUG) - - ch = logging.StreamHandler() - ch.setFormatter(self.formatter) - if IF_DEBUG is not None and IF_DEBUG.lower() == "true": - ch.setLevel(logging.DEBUG) - else: - ch.setLevel(logging.INFO) - self.logger.addHandler(ch) - - hdlr = logging.FileHandler('%s/%s.log' % (self.file_path, logger_name)) - hdlr.setFormatter(self.formatter) - hdlr.setLevel(logging.DEBUG) - self.logger.addHandler(hdlr) - - @property - def get(self): - return self.logger - - -class DashboardLogger(Logger): - file_path = '/var/log/kibana_dashboard' - - def __init__(self, logger_name): - super(DashboardLogger, self).__init__(logger_name) diff --git a/dashboard/dashboard/conf/__init__.py b/dashboard/dashboard/conf/__init__.py deleted file mode 100644 index e69de29..0000000 --- a/dashboard/dashboard/conf/__init__.py +++ /dev/null diff --git a/dashboard/dashboard/conf/config.py b/dashboard/dashboard/conf/config.py deleted file mode 100644 index 6114e90..0000000 --- a/dashboard/dashboard/conf/config.py +++ /dev/null @@ -1,86 +0,0 @@ -#! /usr/bin/env python - -import urlparse -from ConfigParser import SafeConfigParser, NoOptionError - - -class ParseError(Exception): - """ - Custom exception class for config file - """ - - def __init__(self, message): - self.msg = message - - def __str__(self): - return 'error parsing config file : %s' % self.msg - - -class APIConfig: - """ - 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() - """ - - def __init__(self): - self._default_config_location = "/etc/dashboard/config.ini" - self.es_url = 'http://localhost:9200' - self.es_creds = None - self.kibana_url = None - self.js_path = None - self.index_url = None - - def _get_str_parameter(self, section, param): - try: - return self._parser.get(section, param) - except NoOptionError: - raise ParseError("[%s.%s] parameter not found" % (section, param)) - - def _get_int_parameter(self, section, param): - try: - return int(self._get_str_parameter(section, param)) - except ValueError: - raise ParseError("[%s.%s] not an int" % (section, param)) - - def _get_bool_parameter(self, section, param): - result = self._get_str_parameter(section, param) - if str(result).lower() == 'true': - return True - if str(result).lower() == 'false': - return False - - raise ParseError( - "[%s.%s : %s] not a boolean" % (section, param, result)) - - @staticmethod - def parse(config_location=None): - obj = APIConfig() - - if config_location is None: - config_location = obj._default_config_location - - obj._parser = SafeConfigParser() - obj._parser.read(config_location) - if not obj._parser: - raise ParseError("%s not found" % config_location) - - # Linking attributes to keys from file with their sections - obj.es_url = obj._get_str_parameter("elastic", "url") - obj.es_creds = obj._get_str_parameter("elastic", "creds") - obj.kibana_url = obj._get_str_parameter("kibana", "url") - obj.js_path = obj._get_str_parameter("kibana", "js_path") - index = obj._get_str_parameter("elastic", "index") - obj.index_url = urlparse.urljoin(obj.es_url, index) - - return obj - - def __str__(self): - return "elastic_url = %s \n" \ - "elastic_creds = %s \n" \ - "kibana_url = %s \n" \ - "index_url = %s \n" \ - "js_path = %s \n" % (self.es_url, - self.es_creds, - self.kibana_url, - self.index_url, - self.js_path) diff --git a/dashboard/dashboard/conf/testcases.py b/dashboard/dashboard/conf/testcases.py deleted file mode 100644 index 98ce209..0000000 --- a/dashboard/dashboard/conf/testcases.py +++ /dev/null @@ -1,24 +0,0 @@ -import yaml - - -with open('/etc/dashboard/testcases.yaml') as f: - testcases_yaml = yaml.safe_load(f) -f.close() - - -def compose_format(fmt): - return 'format_' + fmt.strip() - - -def get_format(project, case): - testcases = testcases_yaml.get(project) - if isinstance(testcases, list): - for case_dict in testcases: - if case_dict['name'] == case: - return compose_format(case_dict['format']) - return None - - -if __name__ == '__main__': - fmt = get_format('functest', 'vping_ssh') - print(fmt) diff --git a/dashboard/dashboard/elastic2kibana/__init__.py b/dashboard/dashboard/elastic2kibana/__init__.py deleted file mode 100644 index e69de29..0000000 --- a/dashboard/dashboard/elastic2kibana/__init__.py +++ /dev/null diff --git a/dashboard/dashboard/elastic2kibana/dashboard_assembler.py b/dashboard/dashboard/elastic2kibana/dashboard_assembler.py deleted file mode 100644 index 651168b..0000000 --- a/dashboard/dashboard/elastic2kibana/dashboard_assembler.py +++ /dev/null @@ -1,59 +0,0 @@ -import json - -import utility -from dashboard.common import elastic_access - - -class DashboardAssembler(object): - def __init__(self, - project, - case, - family, - installer, - pod, - visualizations, - es_url, - es_creds): - super(DashboardAssembler, self).__init__() - self.project = project - self.case = case - self.test_family = family - self.installer = installer - self.pod = pod - self.visualizations = visualizations - self.es_url = es_url - self.es_creds = es_creds - self._assemble() - self._publish() - - def _assemble(self): - db = { - "query": { - "project_name": self.project, - "case_name": self.case, - "installer": self.installer, - "metric": self.visualizations[0].vis_state_title, - "pod": self.pod - }, - "test_family": self.test_family, - "ids": [visualization.id for visualization in self.visualizations] - } - template = utility.env.get_template('dashboard.json') - self.dashboard = json.loads(template.render(db=db)) - utility.dumps(self.dashboard, - ['description', - 'uiStateJSON', - 'panelsJSON', - 'optionsJSON']) - utility.dumps_2depth(self.dashboard, - 'kibanaSavedObjectMeta', - 'searchSourceJSON') - self.id = self.dashboard['title'].replace(' ', '-').replace('/', '-') - return self - - def _publish(self): - elastic_access.publish_kibana(self.es_url, - self.es_creds, - 'dashboard', - self.id, - self.dashboard) diff --git a/dashboard/dashboard/elastic2kibana/main.py b/dashboard/dashboard/elastic2kibana/main.py deleted file mode 100644 index 112d222..0000000 --- a/dashboard/dashboard/elastic2kibana/main.py +++ /dev/null @@ -1,155 +0,0 @@ -#! /usr/bin/env python -import json - -import argparse - -from dashboard.common import elastic_access -from dashboard.common import logger_utils -from dashboard.conf import config -from dashboard.conf import testcases -from dashboard_assembler import DashboardAssembler -from visualization_assembler import VisualizationAssembler - -logger = logger_utils.DashboardLogger('elastic2kibana').get - -parser = argparse.ArgumentParser() -parser.add_argument("-c", "--config-file", - dest='config_file', - help="Config file location") - -args = parser.parse_args() -CONF = config.APIConfig().parse(args.config_file) - -_installers = {'fuel', 'apex', 'compass', 'joid'} - - -class KibanaConstructor(object): - def __init__(self): - super(KibanaConstructor, self).__init__() - self.js_dict = {} - - def construct(self): - for project, case_dicts in testcases.testcases_yaml.items(): - for case in case_dicts: - self._construct_by_case(project, case) - return self - - def _construct_by_case(self, project, case): - case_name = case.get('name') - vis_ps = case.get('visualizations') - family = case.get('test_family') - for vis_p in vis_ps: - self._construct_by_vis(project, case_name, family, vis_p) - - def _construct_by_vis(self, project, case, family, vis_p): - for installer in _installers: - pods_and_scenarios = self._get_pods_and_scenarios(project, - case, - installer) - for pod, scenarios in pods_and_scenarios.iteritems(): - visualizations = self._construct_visualizations(project, - case, - installer, - pod, - scenarios, - vis_p, - CONF.es_url, - CONF.es_creds) - dashboard = DashboardAssembler(project, - case, - family, - installer, - pod, - visualizations, - CONF.es_url, - CONF.es_creds) - self._set_js_dict(case, - pod, - installer, - family, - vis_p.get('name'), - dashboard.id) - - @staticmethod - def _construct_visualizations(project, - case, - installer, - pod, - scenarios, - vis_p, - es_url, - es_creds): - visualizations = [] - for scenario in scenarios: - visualizations.append(VisualizationAssembler(project, - case, - installer, - pod, - scenario, - vis_p, - es_url, - es_creds)) - return visualizations - - def _set_js_dict(self, case, pod, installer, family, metric, id): - test_label = '{} {}'.format(case, metric) - if family not in self.js_dict: - self.js_dict[family] = {} - - js_test_family = self.js_dict[family] - - if test_label not in js_test_family: - js_test_family[test_label] = {} - - js_test_label = js_test_family[test_label] - - if installer not in js_test_label: - js_test_label[installer] = {} - - js_installer = js_test_label[installer] - js_installer[pod] = CONF.kibana_url + '#/dashboard/' + id - - def config_js(self): - with open(CONF.js_path, 'w+') as conf_js_fdesc: - conf_js_fdesc.write('var kibana_dashboard_links = ') - conf_js_fdesc.write(str(self.js_dict).replace("u'", "'")) - - def _get_pods_and_scenarios(self, project, case, installer): - query = json.JSONEncoder().encode({ - "query": { - "bool": { - "must": [ - {"match_all": {}} - ], - "filter": [ - {"match": {"installer": installer}}, - {"match": {"project_name": project}}, - {"match": {"case_name": case}} - ] - } - } - }) - - elastic_data = elastic_access.get_docs(CONF.index_url, - CONF.es_creds, - query) - - pods_and_scenarios = {} - - for data in elastic_data: - pod = data['pod_name'] - if pod in pods_and_scenarios: - pods_and_scenarios[pod].add(data['scenario']) - else: - pods_and_scenarios[pod] = {data['scenario']} - - if 'all' in pods_and_scenarios: - pods_and_scenarios['all'].add(data['scenario']) - else: - pods_and_scenarios['all'] = {data['scenario']} - - return pods_and_scenarios - - -def main(): - KibanaConstructor().construct().config_js() diff --git a/dashboard/dashboard/elastic2kibana/templates/dashboard.json b/dashboard/dashboard/elastic2kibana/templates/dashboard.json deleted file mode 100644 index cc80995..0000000 --- a/dashboard/dashboard/elastic2kibana/templates/dashboard.json +++ /dev/null @@ -1,61 +0,0 @@ -{% set db = db|default({}) -%} - - -{% macro calc_col(index) -%} - {% if index is divisibleby 2 %} - 7 - {% else %} - 1 - {% endif %} -{%- endmacro %} - -{% macro calc_row(index) -%} -{% set num = (index - 1)//2 %} - {{1 + num * 3}} -{%- endmacro %} - -{ - "description": "Kibana dashboard for {{db.query}}", - "hits": 0, - "kibanaSavedObjectMeta": { - "searchSourceJSON": { - "filter": [ - { - "query": { - "query_string": { - "analyze_wildcard": true, - "query": "*" - } - } - } - ] - } - }, - "metadata": { - "label": "{{db.query.case_name}} {{db.query.metric}}", - "test_family": "{{db.test_family}}" - }, - "optionsJSON": { - "darkTheme": false - }, - "panelsJSON": [ - {% for id in db.ids %} - { - "col": {{calc_col(loop.index)}}, - "id": "{{id}}", - "panelIndex": {{loop.index}}, - "row": {{calc_row(loop.index)}}, - "size_x": 6, - "size_y": 3, - "type": "visualization" - } - {% if not loop.last %} - , - {% endif %} - {% endfor %} - ], - "scenario": 1, - "timeRestore": false, - "title": "{{db.query.project_name}} {{db.query.case_name}} {{db.query.installer}} {{db.query.metric}} {{db.query.pod}}", - "uiStateJSON": {} -} diff --git a/dashboard/dashboard/elastic2kibana/templates/duration.json b/dashboard/dashboard/elastic2kibana/templates/duration.json deleted file mode 100644 index f50a668..0000000 --- a/dashboard/dashboard/elastic2kibana/templates/duration.json +++ /dev/null @@ -1,45 +0,0 @@ -{% set aggs = aggs|default([]) -%} - -{ - "title": "duration", - "type": "line", - "listeners": {}, - "params": { - "addLegend": true, - "shareYAxis": true, - "addTooltip": true, - "smoothLines": false, - "scale": "linear", - "interpolate": "linear", - "times": [], - "addTimeMarker": false, - "defaultYExtents": false, - "setYExtents": false, - "yAxis": {}, - "mode": "stacked" - }, - "aggs": [ - {% for agg in aggs %} - { - "id": {{agg.id }}, - "type": "avg", - "schema": "metric", - "params": { - "field": "{{agg.field}}" - } - }, - {% endfor %} - { - "id": {{ aggs|length + 1 }}, - "type": "date_histogram", - "schema": "segment", - "params": { - "field": "start_date", - "interval": "auto", - "customInterval": "2h", - "min_doc_count": 1, - "extended_bounds": {} - } - } - ] -} diff --git a/dashboard/dashboard/elastic2kibana/templates/qpi.json b/dashboard/dashboard/elastic2kibana/templates/qpi.json deleted file mode 100644 index a46f315..0000000 --- a/dashboard/dashboard/elastic2kibana/templates/qpi.json +++ /dev/null @@ -1,45 +0,0 @@ -{% set aggs = aggs|default([]) -%} - -{ - "title": "qpi", - "type": "line", - "listeners": {}, - "params": { - "addLegend": true, - "shareYAxis": true, - "addTooltip": true, - "smoothLines": false, - "scale": "linear", - "interpolate": "linear", - "times": [], - "addTimeMarker": false, - "defaultYExtents": false, - "setYExtents": false, - "yAxis": {}, - "mode": "stacked" - }, - "aggs": [ - {% for agg in aggs %} - { - "id": {{agg.id }}, - "type": "avg", - "schema": "metric", - "params": { - "field": "{{agg.field}}" - } - }, - {% endfor %} - { - "id": {{ aggs|length + 1 }}, - "type": "date_histogram", - "schema": "segment", - "params": { - "field": "start_date", - "interval": "auto", - "customInterval": "2h", - "min_doc_count": 1, - "extended_bounds": {} - } - } - ] -} diff --git a/dashboard/dashboard/elastic2kibana/templates/success_percentage.json b/dashboard/dashboard/elastic2kibana/templates/success_percentage.json deleted file mode 100644 index 9930708..0000000 --- a/dashboard/dashboard/elastic2kibana/templates/success_percentage.json +++ /dev/null @@ -1,45 +0,0 @@ -{% set aggs = aggs|default([]) -%} - -{ - "title": "success_percentage", - "type": "line", - "listeners": {}, - "params": { - "addLegend": true, - "shareYAxis": true, - "addTooltip": true, - "smoothLines": false, - "scale": "linear", - "interpolate": "linear", - "times": [], - "addTimeMarker": false, - "defaultYExtents": false, - "setYExtents": false, - "yAxis": {}, - "mode": "stacked" - }, - "aggs": [ - {% for agg in aggs %} - { - "id": {{agg.id }}, - "type": "avg", - "schema": "metric", - "params": { - "field": "{{agg.field}}" - } - }, - {% endfor %} - { - "id": {{ aggs|length + 1 }}, - "type": "date_histogram", - "schema": "segment", - "params": { - "field": "start_date", - "interval": "auto", - "customInterval": "2h", - "min_doc_count": 1, - "extended_bounds": {} - } - } - ] -} diff --git a/dashboard/dashboard/elastic2kibana/templates/tests_failures.json b/dashboard/dashboard/elastic2kibana/templates/tests_failures.json deleted file mode 100644 index 01f9ba8..0000000 --- a/dashboard/dashboard/elastic2kibana/templates/tests_failures.json +++ /dev/null @@ -1,45 +0,0 @@ -{% set aggs = aggs|default([]) -%} - -{ - "title": "tests_failures", - "type": "histogram", - "listeners": {}, - "params": { - "addLegend": true, - "shareYAxis": true, - "addTooltip": true, - "smoothLines": false, - "scale": "linear", - "interpolate": "linear", - "times": [], - "addTimeMarker": false, - "defaultYExtents": false, - "setYExtents": false, - "yAxis": {}, - "mode": "grouped" - }, - "aggs": [ - {% for agg in aggs %} - { - "id": {{agg.id }}, - "type": "sum", - "schema": "metric", - "params": { - "field": "{{agg.field}}" - } - }, - {% endfor %} - { - "id": {{ aggs|length + 1 }}, - "type": "date_histogram", - "schema": "segment", - "params": { - "field": "start_date", - "interval": "auto", - "customInterval": "2h", - "min_doc_count": 1, - "extended_bounds": {} - } - } - ] -} diff --git a/dashboard/dashboard/elastic2kibana/templates/visualization.json b/dashboard/dashboard/elastic2kibana/templates/visualization.json deleted file mode 100644 index d51d417..0000000 --- a/dashboard/dashboard/elastic2kibana/templates/visualization.json +++ /dev/null @@ -1,32 +0,0 @@ -{% set vis = vis|default({}) -%} - - -{ - "description": "Kibana visualization for {{ vis.filters }}", - "kibanaSavedObjectMeta": { - "searchSourceJSON": { - "filter": [ - {% for key, value in vis.filters.iteritems() if key != "metric" %} - {% if not (key == "pod_name" and value == "all") %} - { - "match": { - "{{ key }}": { - "query": "{{ value }}", - "type": "phrase" - } - } - } - {% if not loop.last %} - , - {% endif %} - {% endif %} - {% endfor %} - ] - } - }, - "scenario": 1, - "title": "{{vis.filters.project_name}} {{vis.filters.case_name}} {{vis.filters.installer}} {{vis.filters.metric}} {{vis.filters.pod_name}} {{vis.filters.scenario}}", - "uiStateJSON": {}, - "visState": {{ vis.visState }} -} - diff --git a/dashboard/dashboard/elastic2kibana/utility.py b/dashboard/dashboard/elastic2kibana/utility.py deleted file mode 100644 index 40d9202..0000000 --- a/dashboard/dashboard/elastic2kibana/utility.py +++ /dev/null @@ -1,16 +0,0 @@ -import json - -from jinja2 import Environment, PackageLoader - -env = Environment(loader=PackageLoader('dashboard', - 'elastic2kibana/templates')) -env.filters['jsonify'] = json.dumps - - -def dumps(a_dict, items): - for key in items: - a_dict[key] = json.dumps(a_dict[key]) - - -def dumps_2depth(a_dict, key1, key2): - a_dict[key1][key2] = json.dumps(a_dict[key1][key2]) diff --git a/dashboard/dashboard/elastic2kibana/visualization_assembler.py b/dashboard/dashboard/elastic2kibana/visualization_assembler.py deleted file mode 100644 index d7e6e54..0000000 --- a/dashboard/dashboard/elastic2kibana/visualization_assembler.py +++ /dev/null @@ -1,84 +0,0 @@ -import json - -import utility -from dashboard.common import elastic_access - - -class VisStateBuilder(object): - def __init__(self, vis_p): - super(VisStateBuilder, self).__init__() - self.vis_p = vis_p - - def build(self): - name = self.vis_p.get('name') - fields = self.vis_p.get('fields') - - aggs = [] - index = 1 - for field in fields: - aggs.append({ - "id": index, - "field": field.get("field") - }) - index += 1 - - template = utility.env.get_template('{}.json'.format(name)) - vis = template.render(aggs=aggs) - return json.loads(vis) - - -class VisualizationAssembler(object): - def __init__(self, - project, - case, - installer, - pod, - scenario, - vis_p, - es_url, - es_creds): - super(VisualizationAssembler, self).__init__() - self.project = project - self.case = case - self.installer = installer - self.pod = pod - self.scenario = scenario - self.vis_p = vis_p - self.es_url = es_url - self.es_creds = es_creds - self._assemble() - self._publish() - - def _assemble(self): - visState = VisStateBuilder(self.vis_p).build() - self.vis_state_title = visState['title'] - - vis = { - "visState": json.dumps(visState), - "filters": { - "project_name": self.project, - "case_name": self.case, - "installer": self.installer, - "metric": self.vis_state_title, - "pod_name": self.pod, - "scenario": self.scenario - } - } - - template = utility.env.get_template('visualization.json') - - self.visualization = json.loads(template.render(vis=vis)) - utility.dumps(self.visualization, - ['visState', 'description', 'uiStateJSON']) - utility.dumps_2depth(self.visualization, - 'kibanaSavedObjectMeta', - 'searchSourceJSON') - title = self.visualization['title'] - self.id = title.replace(' ', '-').replace('/', '-') - - def _publish(self): - elastic_access.publish_kibana(self.es_url, - self.es_creds, - 'visualization', - self.id, - self.visualization) diff --git a/dashboard/dashboard/functest/__init__.py b/dashboard/dashboard/functest/__init__.py deleted file mode 100644 index e69de29..0000000 --- a/dashboard/dashboard/functest/__init__.py +++ /dev/null diff --git a/dashboard/dashboard/functest/format.py b/dashboard/dashboard/functest/format.py deleted file mode 100644 index 75d361f..0000000 --- a/dashboard/dashboard/functest/format.py +++ /dev/null @@ -1,192 +0,0 @@ -#! /usr/bin/env python - - -def _convert_value(value): - return value if value != '' else 0 - - -def _convert_duration(duration): - if ((isinstance(duration, str) or - isinstance(duration, unicode)) and ':' in duration): - hours, minutes, seconds = duration.split(":") - hours = _convert_value(hours) - minutes = _convert_value(minutes) - seconds = _convert_value(seconds) - int_duration = 3600 * int(hours) + 60 * int(minutes) + float(seconds) - else: - int_duration = duration - return int_duration - - -def format_normal(testcase): - """ - Look for these and leave any of those: - details.duration - details.tests - details.failures - - If none are present, then return False - """ - found = False - testcase_details = testcase['details'] - fields = ['duration', 'tests', 'failures'] - if isinstance(testcase_details, dict): - for key, value in testcase_details.items(): - if key in fields: - found = True - if key == 'duration': - testcase_details[key] = _convert_duration(value) - else: - del testcase_details[key] - - if 'tests' in testcase_details and 'failures' in testcase_details: - testcase_tests = float(testcase_details['tests']) - testcase_failures = float(testcase_details['failures']) - if testcase_tests != 0: - testcase_details['success_percentage'] = 100 * \ - (testcase_tests - testcase_failures) / testcase_tests - else: - testcase_details['success_percentage'] = 0 - - return found - - -def format_rally(testcase): - """ - Structure: - details.[{summary.duration}] - details.[{summary.nb success}] - details.[{summary.nb tests}] - - Find data for these fields - -> details.duration - -> details.tests - -> details.success_percentage - """ - details = testcase['details'] - summary = None - for item in details: - if 'summary' in item: - summary = item['summary'] - - if not summary: - return False - - testcase['details'] = { - 'duration': summary['duration'], - 'tests': summary['nb tests'], - 'success_percentage': summary['nb success'] - } - return True - - -def _get_statistics(orig_data, stat_fields, stat_values=None): - test_results = {} - for stat_data in orig_data: - for field in stat_fields: - stat_value = stat_data[field] - if stat_value in test_results: - test_results[stat_value] += 1 - else: - test_results[stat_value] = 1 - - if stat_values is not None: - for stat_value in stat_values: - if stat_value not in test_results: - test_results[stat_value] = 0 - - return test_results - - -def format_onos(testcase): - """ - Structure: - details.FUNCvirNet.duration - details.FUNCvirNet.status.[{Case result}] - details.FUNCvirNetL3.duration - details.FUNCvirNetL3.status.[{Case result}] - - Find data for these fields - -> details.FUNCvirNet.duration - -> details.FUNCvirNet.tests - -> details.FUNCvirNet.failures - -> details.FUNCvirNetL3.duration - -> details.FUNCvirNetL3.tests - -> details.FUNCvirNetL3.failures - """ - testcase_details = testcase['details'] - - if ('FUNCvirNet' not in testcase_details or - 'FUNCvirNetL3' not in testcase_details): - return False - - funcvirnet_details = testcase_details['FUNCvirNet']['status'] - funcvirnet_stats = _get_statistics( - funcvirnet_details, ('Case result',), ('PASS', 'FAIL')) - funcvirnet_passed = funcvirnet_stats['PASS'] - funcvirnet_failed = funcvirnet_stats['FAIL'] - funcvirnet_all = funcvirnet_passed + funcvirnet_failed - - funcvirnetl3_details = testcase_details['FUNCvirNetL3']['status'] - funcvirnetl3_stats = _get_statistics( - funcvirnetl3_details, ('Case result',), ('PASS', 'FAIL')) - funcvirnetl3_passed = funcvirnetl3_stats['PASS'] - funcvirnetl3_failed = funcvirnetl3_stats['FAIL'] - funcvirnetl3_all = funcvirnetl3_passed + funcvirnetl3_failed - - testcase_details['FUNCvirNet'] = { - 'duration': - _convert_duration(testcase_details['FUNCvirNet']['duration']), - 'tests': funcvirnet_all, - 'failures': funcvirnet_failed - } - testcase_details['FUNCvirNetL3'] = { - 'duration': - _convert_duration(testcase_details['FUNCvirNetL3']['duration']), - 'tests': funcvirnetl3_all, - 'failures': funcvirnetl3_failed - } - return True - - -def format_vims(testcase): - """ - Structure: - details.sig_test.result.[{result}] - details.sig_test.duration - details.vIMS.duration - details.orchestrator.duration - - Find data for these fields - -> details.sig_test.duration - -> details.sig_test.tests - -> details.sig_test.failures - -> details.sig_test.passed - -> details.sig_test.skipped - -> details.vIMS.duration - -> details.orchestrator.duration - """ - testcase_details = testcase['details'] - test_results = _get_statistics(testcase_details['sig_test']['result'], - ('result',), - ('Passed', 'Skipped', 'Failed')) - passed = test_results['Passed'] - skipped = test_results['Skipped'] - failures = test_results['Failed'] - all_tests = passed + skipped + failures - testcase['details'] = { - 'sig_test': { - 'duration': testcase_details['sig_test']['duration'], - 'tests': all_tests, - 'failures': failures, - 'passed': passed, - 'skipped': skipped - }, - 'vIMS': { - 'duration': testcase_details['vIMS']['duration'] - }, - 'orchestrator': { - 'duration': testcase_details['orchestrator']['duration'] - } - } - return True diff --git a/dashboard/dashboard/functest/testcases.yaml b/dashboard/dashboard/functest/testcases.yaml deleted file mode 100644 index 85cb8b2..0000000 --- a/dashboard/dashboard/functest/testcases.yaml +++ /dev/null @@ -1,139 +0,0 @@ ---- -functest: - - - name: tempest_smoke_serial - format: normal - test_family: VIM - visualizations: - - - name: duration - fields: - - field: details.duration - - - name: tests_failures - fields: - - field: details.tests - - field: details.failures - - - name: success_percentage - fields: - - field: details.success_percentage - - - name: rally_sanity - test_family: VIM - format: rally - visualizations: - - - name: duration - fields: - - field: details.duration - - - name: tests_failures - fields: - - field: details.tests - - - name: success_percentage - fields: - - field: details.success_percentage - - - name: vping_ssh - format: normal - test_family: VIM - visualizations: - - - name: duration - fields: - - field: details.duration - - - name: vping_userdata - format: normal - test_family: VIM - visualizations: - - - name: duration - fields: - - field: details.duration - - - name: odl - test_family: Controller - format: odl - visualizations: - - - name: tests_failures - fields: - - field: details.tests - - field: details.failures - - - name: success_percentage - fields: - - field: details.success_percentage - - - name: onos - format: onos - test_family: Controller - visualizations: - - - name: duration - label: FUNCvirNet - fields: - - field: details.FUNCvirNet.duration - - - name: duration - label: FUNCvirNetL3 - fields: - - field: details.FUNCvirNetL3.duration - - - name: tests_failures - label: FUNCvirNet - fields: - - field: details.FUNCvirNet.tests - - field: details.FUNCvirNet.failures - - - name: tests_failures - label: FUNCvirNetL3 - fields: - - field: details.FUNCvirNetL3.tests - - field: details.FUNCvirNetL3.failures - - - name: vims - format: vims - test_family: Features - visualizations: - - - name: duration - fields: - - field: details.vIMS.duration - - field: details.orchestrator.duration - - field: details.sig_test.duration - - - name: tests_failures - fields: - - field: details.sig_test.tests - - field: details.sig_test.failures - - field: details.sig_test.passed - - field: details.sig_test.skipped -promise: - - - name: promise - format: normal - test_family: Features - visualizations: - - - name: duration - fields: - - field: details.duration - - - name: tests_failures - fields: - - field: details.tests - - field: details.failures -doctor: - - - name: doctor-notification - test_family: Features - format: normal - visualizations: - - - name: duration - fields: - - field: details.duration diff --git a/dashboard/dashboard/mongo2elastic/__init__.py b/dashboard/dashboard/mongo2elastic/__init__.py deleted file mode 100644 index e69de29..0000000 --- a/dashboard/dashboard/mongo2elastic/__init__.py +++ /dev/null diff --git a/dashboard/dashboard/mongo2elastic/main.py b/dashboard/dashboard/mongo2elastic/main.py deleted file mode 100644 index e33252d..0000000 --- a/dashboard/dashboard/mongo2elastic/main.py +++ /dev/null @@ -1,259 +0,0 @@ -#! /usr/bin/env python - -import datetime -import json -import os -import subprocess -import traceback -import uuid - -import argparse - -from dashboard.common import elastic_access -from dashboard.common import logger_utils -from dashboard.conf import testcases -from dashboard.conf.config import APIConfig -from dashboard.mongo2elastic import format - -logger = logger_utils.DashboardLogger('mongo2elastic').get - -parser = argparse.ArgumentParser() -parser.add_argument("-c", "--config-file", - dest='config_file', - help="Config file location") -parser.add_argument('-ld', '--latest-days', - default=0, - type=int, - metavar='N', - help='get entries old at most N days from mongodb and' - ' parse those that are not already in elasticsearch.' - ' If not present, will get everything from mongodb,' - ' which is the default') - -args = parser.parse_args() -CONF = APIConfig().parse(args.config_file) - - -tmp_docs_file = './mongo-{}.json'.format(uuid.uuid4()) - - -class DocumentVerification(object): - - def __init__(self, doc): - super(DocumentVerification, self).__init__() - self.doc = doc - self.doc_id = doc['_id'] if '_id' in doc else None - self.skip = False - - def mandatory_fields_exist(self): - mandatory_fields = ['installer', - 'pod_name', - 'version', - 'case_name', - 'project_name', - 'details', - 'start_date', - 'scenario'] - for key, value in self.doc.items(): - if key in mandatory_fields: - if value is None: - logger.info("Skip testcase '%s' because field " - "'%s' missing" % (self.doc_id, key)) - self.skip = True - else: - mandatory_fields.remove(key) - else: - del self.doc[key] - - if len(mandatory_fields) > 0: - logger.info("Skip testcase '%s' because field(s) '%s' missing" % - (self.doc_id, mandatory_fields)) - self.skip = True - - return self - - def modify_start_date(self): - field = 'start_date' - if field in self.doc: - self.doc[field] = self._fix_date(self.doc[field]) - - return self - - def modify_scenario(self): - scenario = 'scenario' - version = 'version' - - if (scenario not in self.doc) or \ - (scenario in self.doc and self.doc[scenario] is None): - self.doc[scenario] = self.doc[version] - - return self - - def is_skip(self): - return self.skip - - def _fix_date(self, date_string): - if date_string == 'None': - return None - if isinstance(date_string, dict): - return date_string['$date'] - if 'T' not in date_string: - date_string = date_string[:-3].replace(' ', 'T') - if not date_string.endswith('Z'): - date_string += 'Z' - - return date_string - - -class DocumentPublisher(object): - - def __init__(self, doc, fmt, exist_docs, creds, elastic_url): - self.doc = doc - self.fmt = fmt - self.creds = creds - self.exist_docs = exist_docs - self.elastic_url = elastic_url - self.is_formatted = True - - def format(self): - try: - if self._verify_document() and self.fmt: - self.is_formatted = vars(format)[self.fmt](self.doc) - else: - self.is_formatted = False - except Exception: - logger.error("Fail in format testcase[%s]\nerror message: %s" % - (self.doc, traceback.format_exc())) - self.is_formatted = False - finally: - return self - - def publish(self): - if self.is_formatted and self.doc not in self.exist_docs: - self._publish() - - def _publish(self): - status, data = elastic_access.publish_docs( - self.elastic_url, self.creds, self.doc) - if status > 300: - logger.error('Publish record[{}] failed, due to [{}]' - .format(self.doc, - json.loads(data)['error']['reason'])) - - def _fix_date(self, date_string): - if isinstance(date_string, dict): - return date_string['$date'] - else: - return date_string[:-3].replace(' ', 'T') + 'Z' - - def _verify_document(self): - return not (DocumentVerification(self.doc) - .modify_start_date() - .modify_scenario() - .mandatory_fields_exist() - .is_skip()) - - -class DocumentsPublisher(object): - - def __init__(self, project, case, fmt, days, elastic_url, creds): - self.project = project - self.case = case - self.fmt = fmt - self.days = days - self.elastic_url = elastic_url - self.creds = creds - self.existed_docs = [] - - def export(self): - if self.days > 0: - past_time = datetime.datetime.today( - ) - datetime.timedelta(days=self.days) - query = '''{{ - "project_name": "{}", - "case_name": "{}", - "start_date": {{"$gt" : "{}"}} - }}'''.format(self.project, self.case, past_time) - else: - query = '''{{ - "project_name": "{}", - "case_name": "{}" - }}'''.format(self.project, self.case) - cmd = ['mongoexport', - '--db', 'test_results_collection', - '--collection', 'results', - '--query', '{}'.format(query), - '--out', '{}'.format(tmp_docs_file)] - try: - subprocess.check_call(cmd) - return self - except Exception as err: - logger.error("export mongodb failed: %s" % err) - self._remove() - exit(-1) - - def get_exists(self): - if self.days == 0: - body = '''{{ - "query": {{ - "bool": {{ - "must": [ - {{ "match": {{ "project_name": "{}" }} }}, - {{ "match": {{ "case_name": "{}" }} }} - ] - }} - }} - }}'''.format(self.project, self.case) - elif self.days > 0: - body = '''{{ - "query": {{ - "bool": {{ - "must": [ - {{ "match": {{ "project_name": "{}" }} }}, - {{ "match": {{ "case_name": "{}" }} }} - ], - "filter": {{ - "range": {{ - "start_date": {{ "gte": "now-{}d" }} - }} - }} - }} - }} - }}'''.format(self.project, self.case, self.days) - else: - raise Exception('Update days must be non-negative') - self.existed_docs = elastic_access.get_docs( - self.elastic_url, self.creds, body) - return self - - def publish(self): - fdocs = None - try: - with open(tmp_docs_file) as fdocs: - for doc_line in fdocs: - DocumentPublisher(json.loads(doc_line), - self.fmt, - self.existed_docs, - self.creds, - self.elastic_url).format().publish() - finally: - if fdocs: - fdocs.close() - self._remove() - - def _remove(self): - if os.path.exists(tmp_docs_file): - os.remove(tmp_docs_file) - - -def main(): - for project, case_dicts in testcases.testcases_yaml.items(): - for case_dict in case_dicts: - case = case_dict.get('name') - fmt = testcases.compose_format(case_dict.get('format')) - DocumentsPublisher(project, - case, - fmt, - args.latest_days, - CONF.index_url, - CONF.es_creds).export().get_exists().publish() diff --git a/dashboard/dashboard/qtip/__init__.py b/dashboard/dashboard/qtip/__init__.py deleted file mode 100644 index e69de29..0000000 --- a/dashboard/dashboard/qtip/__init__.py +++ /dev/null diff --git a/dashboard/dashboard/qtip/format.py b/dashboard/dashboard/qtip/format.py deleted file mode 100644 index b78fa5b..0000000 --- a/dashboard/dashboard/qtip/format.py +++ /dev/null @@ -1,19 +0,0 @@ -#! /usr/bin/env python - - -def format_qpi(testcase): - """ - Look for these and leave any of those: - details.index - - If none are present, then return False - """ - details = testcase['details'] - if 'index' not in details: - return False - - for key, value in details.items(): - if key != 'index': - del details[key] - - return True diff --git a/dashboard/dashboard/qtip/testcases.yaml b/dashboard/dashboard/qtip/testcases.yaml deleted file mode 100644 index dfa9cc2..0000000 --- a/dashboard/dashboard/qtip/testcases.yaml +++ /dev/null @@ -1,29 +0,0 @@ ---- -qtip: - - - name: compute_test_suite - format: qpi - test_family: compute - visualizations: - - - name: qpi - fields: - - field: details.index - - - name: network_test_suite - test_family: network - format: qpi - visualizations: - - - name: qpi - fields: - - field: details.index - - - name: storage_test_suite - format: qpi - test_family: storage - visualizations: - - - name: qpi - fields: - - field: details.index diff --git a/dashboard/etc/config.ini b/dashboard/etc/config.ini deleted file mode 100644 index 77adc16..0000000 --- a/dashboard/etc/config.ini +++ /dev/null @@ -1,10 +0,0 @@ -# to add a new parameter in the config file, -# the CONF object in config.ini must be updated -[elastic] -url = http://localhost:9200 -index = testapi/results -creds = - -[kibana] -url = http://10.63.243.17:5601/app/kibana -js_path = /usr/share/nginx/html/kibana_dashboards/conf.js diff --git a/dashboard/install.sh b/dashboard/install.sh deleted file mode 100755 index 9fd60d9..0000000 --- a/dashboard/install.sh +++ /dev/null @@ -1,54 +0,0 @@ -#!/bin/bash - -usage=" -Script to install dashboard automatically. -This script should be run under root. - -usage: - bash $(basename "$0") [-h|--help] [-t <test_name>] - -where: - -h|--help show this help text - -p|--project project dashboard - <project_name>" - -# Parse parameters -while [[ $# > 0 ]] - do - key="$1" - case $key in - -h|--help) - echo "$usage" - exit 0 - shift - ;; - -p|--project) - PROJECT="$2" - shift - ;; - *) - echo "unknown option $1 $2" - exit 1 - ;; - esac - shift # past argument or value -done - -if [[ $(whoami) != "root" ]]; then - echo "Error: This script must be run as root!" - exit 1 -fi - -if [ -z ${PROJECT+x} ]; then - echo "project must be specified" - exit 1 -fi - -if [ $PROJECT != "functest" ] && [ $PROJECT != "qtip" ];then - echo "unsupported project $PROJECT" - exit 1 -fi - -cp -f dashboard/$PROJECT/format.py dashboard/mongo2elastic -cp -f dashboard/$PROJECT/testcases.yaml etc/ -python setup.py install diff --git a/dashboard/kibana_cleanup.py b/dashboard/kibana_cleanup.py deleted file mode 100644 index 7e3662c..0000000 --- a/dashboard/kibana_cleanup.py +++ /dev/null @@ -1,46 +0,0 @@ -#! /usr/bin/env python -import logging -import urlparse - -import argparse - -from dashboard.common import elastic_access - -logger = logging.getLogger('clear_kibana') -logger.setLevel(logging.DEBUG) -file_handler = logging.FileHandler('/var/log/{}.log'.format('clear_kibana')) -file_handler.setFormatter(logging.Formatter('%(asctime)s %(levelname)s: ' - '%(message)s')) -logger.addHandler(file_handler) - - -def delete_all(url, es_creds): - ids = elastic_access.get_docs(url, es_creds, body=None, field='_id') - for id in ids: - del_url = '/'.join([url, id]) - elastic_access.delete_docs(del_url, es_creds) - - -if __name__ == '__main__': - parser = argparse.ArgumentParser( - description=('Delete saved kibana searches, ' - 'visualizations and dashboards')) - parser.add_argument('-e', '--elasticsearch-url', - default='http://localhost:9200', - help=('the url of elasticsearch, ' - 'defaults to http://localhost:9200')) - - parser.add_argument('-u', '--elasticsearch-username', default=None, - help=('The username with password for elasticsearch ' - 'in format username:password')) - - args = parser.parse_args() - base_elastic_url = args.elasticsearch_url - es_creds = args.elasticsearch_username - - urls = (urlparse.urljoin(base_elastic_url, '/.kibana/visualization'), - urlparse.urljoin(base_elastic_url, '/.kibana/dashboard'), - urlparse.urljoin(base_elastic_url, '/.kibana/search')) - - for url in urls: - delete_all(url, es_creds) diff --git a/dashboard/setup.cfg b/dashboard/setup.cfg deleted file mode 100644 index 859dcc0..0000000 --- a/dashboard/setup.cfg +++ /dev/null @@ -1,44 +0,0 @@ -[metadata] -name = dashboard -summary = Test Result Collector -description-file = - README.rst -author = SerenaFeng -author-email = feng.xiaowei@zte.com.cn -#home-page = http://www.opnfv.org/ -license = Apache-2.0 -classifier = - Environment :: opnfv - Intended Audience :: Information Technology - Intended Audience :: System Administrators - License :: OSI Approved :: Apache Software License - Operating System :: POSIX :: Linux - Programming Language :: Python - Programming Language :: Python :: 2 - Programming Language :: Python :: 2.7 - -[global] -setup-hooks = - pbr.hooks.setup_hook - -[files] -packages = - dashboard -package_data = - dashboard = - elastic2kibana/templates/*.* -data_files = - /etc/dashboard = - etc/config.ini - etc/testcases.yaml - -[entry_points] -console_scripts = - dashboard_mongo2elastic = dashboard.mongo2elastic.main:main - dashboard_elastic2kibana = dashboard.elastic2kibana.main:main - -[egg_info] -tag_build = -tag_date = 0 -tag_svn_revision = 0 - diff --git a/dashboard/setup.py b/dashboard/setup.py deleted file mode 100644 index 59637a5..0000000 --- a/dashboard/setup.py +++ /dev/null @@ -1,8 +0,0 @@ -import setuptools - -__author__ = 'serena' - - -setuptools.setup( - setup_requires=['pbr>=1.8'], - pbr=True) diff --git a/reporting/docker/Dockerfile b/reporting/docker/Dockerfile index 07440ad..630a4d8 100644 --- a/reporting/docker/Dockerfile +++ b/reporting/docker/Dockerfile @@ -21,7 +21,7 @@ LABEL version="1.0" description="OPNFV Test Reporting Docker container" ARG BRANCH=master ENV HOME /home/opnfv -ENV working_dir ${HOME}/releng/utils/test/reporting +ENV working_dir ${HOME}/releng-testresults/reporting ENV CONFIG_REPORTING_YAML ${working_dir}/reporting/reporting.yaml WORKDIR ${HOME} @@ -40,7 +40,7 @@ supervisor \ RUN pip install --upgrade pip && easy_install -U setuptools==30.0.0 -RUN git clone --depth 1 https://gerrit.opnfv.org/gerrit/releng /home/opnfv/releng +RUN git clone --depth 1 https://gerrit.opnfv.org/gerrit/releng-testresults /home/opnfv/releng-testresults RUN pip install -r ${working_dir}/requirements.txt RUN sh -c 'curl -sL https://deb.nodesource.com/setup_8.x | bash -' \ diff --git a/reporting/docker/nginx.conf b/reporting/docker/nginx.conf index 66bd7e4..7a41640 100644 --- a/reporting/docker/nginx.conf +++ b/reporting/docker/nginx.conf @@ -11,7 +11,7 @@ server { server_name localhost; location / { - alias /home/opnfv/releng/utils/test/reporting/pages/dist/; + alias /home/opnfv/releng-testresults/reporting/pages/dist/; } location /api/ { @@ -19,6 +19,6 @@ server { } location /display/ { - alias /home/opnfv/releng/utils/test/reporting/display/; + alias /home/opnfv/releng-testresults/reporting/display/; } } diff --git a/reporting/docker/supervisor.conf b/reporting/docker/supervisor.conf index 49310d4..830749d 100644 --- a/reporting/docker/supervisor.conf +++ b/reporting/docker/supervisor.conf @@ -3,7 +3,7 @@ nodaemon = true [program:tornado] user = root -directory = /home/opnfv/releng/utils/test/reporting/api +directory = /home/opnfv/releng-testresults/reporting/api command = python server.py --port=800%(process_num)d process_name=%(program_name)s%(process_num)d numprocs=4 @@ -15,5 +15,5 @@ command = service nginx restart [program:configuration] user = root -directory = /home/opnfv/releng/utils/test/reporting/pages +directory = /home/opnfv/releng-testresults/reporting/pages command = bash config.sh diff --git a/reporting/docker/web_server.sh b/reporting/docker/web_server.sh index 0dd8df7..065c991 100755 --- a/reporting/docker/web_server.sh +++ b/reporting/docker/web_server.sh @@ -3,11 +3,11 @@ cp -r display /usr/share/nginx/html # nginx config -cp /home/opnfv/releng/utils/test/reporting/docker/nginx.conf /etc/nginx/conf.d/ +cp /home/opnfv/releng-testresults/reporting/docker/nginx.conf /etc/nginx/conf.d/ echo "daemon off;" >> /etc/nginx/nginx.conf # supervisor config -cp /home/opnfv/releng/utils/test/reporting/docker/supervisor.conf /etc/supervisor/conf.d/ +cp /home/opnfv/releng-testresults/reporting/docker/supervisor.conf /etc/supervisor/conf.d/ # Manage Angular front end cd pages && /bin/bash angular.sh diff --git a/reporting/reporting/yardstick/template/index-status-tmpl.html b/reporting/reporting/yardstick/template/index-status-tmpl.html index 3db32e5..f7804dd 100644 --- a/reporting/reporting/yardstick/template/index-status-tmpl.html +++ b/reporting/reporting/yardstick/template/index-status-tmpl.html @@ -70,6 +70,7 @@ <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@x86.html">Fuel@x86</a></li> <li><a href="status-fuel@aarch64.html">Fuel@aarch64</a></li> <li><a href="status-joid.html">Joid</a></li> diff --git a/reporting/requirements.txt b/reporting/requirements.txt index 344064d..a01d1dc 100644 --- a/reporting/requirements.txt +++ b/reporting/requirements.txt @@ -1,5 +1,5 @@ pdfkit>=0.6.1 # MIT -wkhtmltopdf-pack>=0.12.3 # MIT +wkhtmltopdf-pack==0.12.2.4 # MIT PyYAML>=3.10.0 # MIT simplejson>=2.2.0 # MIT Jinja2!=2.9.0,!=2.9.1,!=2.9.2,!=2.9.3,!=2.9.4,>=2.8 # BSD License (3 clause) diff --git a/testapi/docker/Dockerfile b/testapi/docker/Dockerfile index 25deb26..bbf12fc 100644 --- a/testapi/docker/Dockerfile +++ b/testapi/docker/Dockerfile @@ -40,12 +40,13 @@ python-pip \ crudini \ --no-install-recommends -RUN pip install --upgrade pip +RUN pip install --upgrade pip requests RUN git config --global http.sslVerify false RUN git clone https://gerrit.opnfv.org/gerrit/releng-testresults /home/releng-testresults WORKDIR /home/releng-testresults/testapi RUN pip install -r requirements.txt + RUN python setup.py install CMD ["bash", "docker/start-server.sh"] diff --git a/testapi/docker/prepare-env.sh b/testapi/docker/prepare-env.sh index 92a0c9f..9086e77 100755 --- a/testapi/docker/prepare-env.sh +++ b/testapi/docker/prepare-env.sh @@ -9,6 +9,11 @@ fi if [ "$base_url" != "" ]; then sudo crudini --set --existing $FILE api url $base_url/api/v1 sudo crudini --set --existing $FILE ui url $base_url - sudo echo "{\"testapiApiUrl\": \"$base_url/api/v1\"}" > \ - /usr/local/share/opnfv_testapi/testapi-ui/config.json + sudo cat > /usr/local/share/opnfv_testapi/testapi-ui/config.json << EOF +{ + "testapiApiUrl": "$base_url/api/v1", + "authenticate": true +} +EOF + fi diff --git a/testapi/opnfv_testapi/common/check.py b/testapi/opnfv_testapi/common/check.py index 8a76f17..9b3ab01 100644 --- a/testapi/opnfv_testapi/common/check.py +++ b/testapi/opnfv_testapi/common/check.py @@ -21,7 +21,7 @@ from opnfv_testapi.db import api as dbapi def is_authorized(method): @functools.wraps(method) def wrapper(self, *args, **kwargs): - if CONF.api_authenticate and self.table in ['pods', 'projects']: + if CONF.api_authenticate and self.table in ['pods', 'projects', 'testcases', 'scenarios']: testapi_id = self.get_secure_cookie(constants.TESTAPI_ID) if not testapi_id: raises.Unauthorized(message.not_login()) @@ -158,3 +158,17 @@ def updated_one_not_exist(xstep): ret = yield gen.coroutine(xstep)(self, data, *args, **kwargs) raise gen.Return(ret) return wrap + + +def query_by_name(xstep): + @functools.wraps(xstep) + def wrap(self, *args, **kwargs): + if 'name' in self.request.query_arguments.keys(): + query = kwargs.get('query', {}) + query.update({'name': re.compile(self.get_query_argument('name'), re.IGNORECASE)}) + kwargs.update({'query': query}) + + ret = yield gen.coroutine(xstep)(self, *args, **kwargs) + raise gen.Return(ret) + + return wrap diff --git a/testapi/opnfv_testapi/handlers/base_handlers.py b/testapi/opnfv_testapi/handlers/base_handlers.py index a2fdb19..537077d 100644 --- a/testapi/opnfv_testapi/handlers/base_handlers.py +++ b/testapi/opnfv_testapi/handlers/base_handlers.py @@ -47,6 +47,7 @@ class GenericApiHandler(web.RequestHandler): self.db_testcases = 'testcases' self.db_results = 'results' self.db_scenarios = 'scenarios' + self.db_deployresults = 'deployresults' self.auth = self.settings["auth"] def prepare(self): @@ -92,7 +93,7 @@ class GenericApiHandler(web.RequestHandler): if k != 'query': data.__setattr__(k, v) - if self.table != 'results': + if 'results' not in self.table: data.creation_date = datetime.now() _id = yield dbapi.db_save(self.table, data.format()) if 'name' in self.json_args: @@ -103,7 +104,8 @@ class GenericApiHandler(web.RequestHandler): @web.asynchronous @gen.coroutine - def _list(self, query=None, res_op=None, *args, **kwargs): + @check.query_by_name + def _list(self, query=None, **kwargs): sort = kwargs.get('sort') page = kwargs.get('page', 0) last = kwargs.get('last', 0) @@ -131,10 +133,7 @@ class GenericApiHandler(web.RequestHandler): cursor = dbapi.db_aggregate(self.table, pipelines) while (yield cursor.fetch_next): data.append(self.format_data(cursor.next_object())) - if res_op is None: - res = {self.table: data} - else: - res = res_op(data, *args) + res = {self.table: data} if page > 0: res.update({ 'pagination': { @@ -201,6 +200,7 @@ class GenericApiHandler(web.RequestHandler): @gen.coroutine @check.no_body @check.not_exist + @check.is_authorized @check.updated_one_not_exist def pure_update(self, data, query=None, **kwargs): data = self.table_cls.from_dict(data) diff --git a/testapi/opnfv_testapi/handlers/deploy_result_handlers.py b/testapi/opnfv_testapi/handlers/deploy_result_handlers.py new file mode 100644 index 0000000..973bfef --- /dev/null +++ b/testapi/opnfv_testapi/handlers/deploy_result_handlers.py @@ -0,0 +1,115 @@ +from opnfv_testapi.handlers import result_handlers +from opnfv_testapi.models import deploy_result_models +from opnfv_testapi.tornado_swagger import swagger + + +class GenericDeployResultHandler(result_handlers.GenericResultHandler): + def __init__(self, application, request, **kwargs): + super(GenericDeployResultHandler, self).__init__(application, + request, + **kwargs) + self.table = self.db_deployresults + self.table_cls = deploy_result_models.DeployResult + + +class DeployResultsHandler(GenericDeployResultHandler): + @swagger.operation(nickname="queryDeployResults") + def get(self): + """ + @description: Retrieve deployment result(s). + @notes: Retrieve deployment result(s). + Available filters for this request are : + - installer : fuel/apex/compass/joid/daisy + - version : platform version (Arno-R1, ...) + - pod_name : pod name + - job_name : jenkins job name + - build_id : Jenkins build id + - scenario : the test scenario + - period : x last days, incompatible with from/to + - from : starting time in 2016-01-01 or 2016-01-01 00:01:23 + - to : ending time in 2016-01-01 or 2016-01-01 00:01:23 + - criteria : the global criteria status passed or failed + - page : which page to list, default to 1 + - descend : true, newest2oldest; false, oldest2newest + + GET /deployresults/installer=daisy&version=master \ + &pod_name=pod_name&period=15 + @return 200: all deployment results consist with query, + empty list if no result is found + @rtype: L{DeployResults} + @param installer: installer name + @type installer: L{string} + @in installer: query + @required installer: False + @param version: version name + @type version: L{string} + @in version: query + @required version: False + @param pod_name: pod name + @type pod_name: L{string} + @in pod_name: query + @required pod_name: False + @param job_name: jenkins job name + @type job_name: L{string} + @in job_name: query + @required job_name: False + @param build_id: jenkins build_id + @type build_id: L{string} + @in build_id: query + @required build_id: False + @param scenario: i.e. odl + @type scenario: L{string} + @in scenario: query + @required scenario: False + @param criteria: i.e. PASS/FAIL + @type criteria: L{string} + @in criteria: query + @required criteria: False + @param period: last days + @type period: L{string} + @in period: query + @required period: False + @param from: i.e. 2016-01-01 or 2016-01-01 00:01:23 + @type from: L{string} + @in from: query + @required from: False + @param to: i.e. 2016-01-01 or 2016-01-01 00:01:23 + @type to: L{string} + @in to: query + @required to: False + @param page: which page to list, default to 1 + @type page: L{int} + @in page: query + @required page: False + @param descend: true, newest2oldest; false, oldest2newest + @type descend: L{string} + @in descend: query + @required descend: False + """ + super(DeployResultsHandler, self).get() + + @swagger.operation(nickname="createDeployResult") + def post(self): + """ + @description: create a deployment result + @param body: deployment result to be created + @type body: L{DeployResultCreateRequest} + @in body: body + @rtype: L{CreateResponse} + @return 200: deploy result is created. + @raise 404: pod not exist + @raise 400: body or some field is not provided + """ + def pod_query(): + return {'name': self.json_args.get('pod_name')} + + def options_check(field, options): + return self.json_args.get(field).upper() in options + + miss_fields = ['pod_name', 'installer', 'scenario'] + carriers = [('pods', pod_query)] + values_check = [('criteria', options_check, ['PASS', 'FAIL'])] + + self._create(miss_fields=miss_fields, + carriers=carriers, + values_check=values_check) diff --git a/testapi/opnfv_testapi/handlers/pod_handlers.py b/testapi/opnfv_testapi/handlers/pod_handlers.py index 06a8b17..03c2033 100644 --- a/testapi/opnfv_testapi/handlers/pod_handlers.py +++ b/testapi/opnfv_testapi/handlers/pod_handlers.py @@ -6,7 +6,6 @@ # which accompanies this distribution, and is available at # http://www.apache.org/licenses/LICENSE-2.0 ############################################################################## -import re from opnfv_testapi.handlers import base_handlers from opnfv_testapi.models import pod_models @@ -19,14 +18,6 @@ class GenericPodHandler(base_handlers.GenericApiHandler): self.table = 'pods' self.table_cls = pod_models.Pod - def set_query(self): - query = dict() - for k in self.request.query_arguments.keys(): - v = self.get_query_argument(k) - if k == 'name': - query['name'] = re.compile(v, re.IGNORECASE) - return query - class PodCLHandler(GenericPodHandler): @swagger.operation(nickname='listAllPods') @@ -40,7 +31,7 @@ class PodCLHandler(GenericPodHandler): @in name: query @required name: False """ - self._list(query=self.set_query()) + self._list() @swagger.operation(nickname='createPod') def post(self): diff --git a/testapi/opnfv_testapi/handlers/project_handlers.py b/testapi/opnfv_testapi/handlers/project_handlers.py index 3ba1a80..0800ee8 100644 --- a/testapi/opnfv_testapi/handlers/project_handlers.py +++ b/testapi/opnfv_testapi/handlers/project_handlers.py @@ -6,7 +6,6 @@ # which accompanies this distribution, and is available at # http://www.apache.org/licenses/LICENSE-2.0 ############################################################################## -import re from opnfv_testapi.handlers import base_handlers from opnfv_testapi.models import project_models @@ -21,14 +20,6 @@ class GenericProjectHandler(base_handlers.GenericApiHandler): self.table = 'projects' self.table_cls = project_models.Project - def set_query(self): - query = dict() - for k in self.request.query_arguments.keys(): - v = self.get_query_argument(k) - if k == 'name': - query['name'] = re.compile(v, re.IGNORECASE) - return query - class ProjectCLHandler(GenericProjectHandler): @swagger.operation(nickname="listProjects") @@ -47,7 +38,7 @@ class ProjectCLHandler(GenericProjectHandler): @in name: query @required name: False """ - self._list(query=self.set_query()) + self._list() @swagger.operation(nickname="createProject") def post(self): diff --git a/testapi/opnfv_testapi/handlers/result_handlers.py b/testapi/opnfv_testapi/handlers/result_handlers.py index c4b61ff..b0691cd 100644 --- a/testapi/opnfv_testapi/handlers/result_handlers.py +++ b/testapi/opnfv_testapi/handlers/result_handlers.py @@ -58,6 +58,8 @@ class GenericResultHandler(base_handlers.GenericApiHandler): date_range.update({'$gte': str(v)}) elif k == 'to': date_range.update({'$lt': str(v)}) + elif 'build_id' in k: + query[k] = self.get_int(k, v) elif k == 'signed': username = self.get_secure_cookie(constants.TESTAPI_ID) role = self.get_secure_cookie(constants.ROLE) @@ -77,6 +79,26 @@ class GenericResultHandler(base_handlers.GenericApiHandler): return query + def get(self): + def descend_limit(): + descend = self.get_query_argument('descend', 'true') + return -1 if descend.lower() == 'true' else 1 + + def last_limit(): + return self.get_int('last', self.get_query_argument('last', 0)) + + def page_limit(): + return self.get_int('page', self.get_query_argument('page', 1)) + + limitations = { + 'sort': {'_id': descend_limit()}, + 'last': last_limit(), + 'page': page_limit(), + 'per_page': CONF.api_results_per_page + } + + self._list(query=self.set_query(), **limitations) + class ResultsCLHandler(GenericResultHandler): @swagger.operation(nickname="queryTestResults") @@ -171,24 +193,7 @@ class ResultsCLHandler(GenericResultHandler): @in descend: query @required descend: False """ - def descend_limit(): - descend = self.get_query_argument('descend', 'true') - return -1 if descend.lower() == 'true' else 1 - - def last_limit(): - return self.get_int('last', self.get_query_argument('last', 0)) - - def page_limit(): - return self.get_int('page', self.get_query_argument('page', 1)) - - limitations = { - 'sort': {'_id': descend_limit()}, - 'last': last_limit(), - 'page': page_limit(), - 'per_page': CONF.api_results_per_page - } - - self._list(query=self.set_query(), **limitations) + super(ResultsCLHandler, self).get() @swagger.operation(nickname="createTestResult") def post(self): @@ -202,9 +207,6 @@ class ResultsCLHandler(GenericResultHandler): @raise 404: pod/project/testcase not exist @raise 400: body/pod_name/project_name/case_name not provided """ - self._post() - - def _post(self): def pod_query(): return {'name': self.json_args.get('pod_name')} @@ -255,7 +257,7 @@ class ResultsUploadHandler(ResultsCLHandler): if openid: self.json_args['user'] = openid - super(ResultsUploadHandler, self)._post() + super(ResultsUploadHandler, self).post() class ResultsGURHandler(GenericResultHandler): diff --git a/testapi/opnfv_testapi/models/base_models.py b/testapi/opnfv_testapi/models/base_models.py index 27396d1..efce0ad 100644 --- a/testapi/opnfv_testapi/models/base_models.py +++ b/testapi/opnfv_testapi/models/base_models.py @@ -22,6 +22,12 @@ from opnfv_testapi.tornado_swagger import swagger class ModelBase(object): + def __eq__(self, other): + res = all(getattr(self, k) == getattr(other, k) + for k in self.format().keys() + if k not in ['_id', 'creation_date']) + return res + def format(self): return self._format(['_id']) @@ -36,15 +42,16 @@ class ModelBase(object): 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) + if k in t.__dict__: + 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 diff --git a/testapi/opnfv_testapi/models/deploy_result_models.py b/testapi/opnfv_testapi/models/deploy_result_models.py new file mode 100644 index 0000000..d717454 --- /dev/null +++ b/testapi/opnfv_testapi/models/deploy_result_models.py @@ -0,0 +1,53 @@ +from opnfv_testapi.models import base_models +from opnfv_testapi.tornado_swagger import swagger + + +@swagger.model() +class DeployResultCreateRequest(base_models.ModelBase): + def __init__(self, + installer=None, + version=None, + pod_name=None, + job_name=None, + build_id=None, + scenario=None, + upstream_job_name=None, + upstream_build_id=None, + criteria=None, + start_date=None, + stop_date=None, + details=None): + self.installer = installer + self.version = version + self.pod_name = pod_name + self.job_name = job_name + self.build_id = build_id + self.scenario = scenario + self.upstream_job_name = upstream_job_name + self.upstream_build_id = upstream_build_id + self.criteria = criteria + self.start_date = start_date + self.stop_date = stop_date + self.details = details + + +@swagger.model() +class DeployResult(DeployResultCreateRequest): + def __init__(self, + _id=None, **kwargs): + self._id = _id + super(DeployResult, self).__init__(**kwargs) + + +@swagger.model() +class DeployResults(base_models.ModelBase): + """ + @property deployresults: + @ptype deployresults: C{list} of L{DeployResult} + """ + def __init__(self): + self.deployresults = list() + + @staticmethod + def attr_parser(): + return {'deployresults': DeployResult} diff --git a/testapi/opnfv_testapi/models/pod_models.py b/testapi/opnfv_testapi/models/pod_models.py index 15c2833..0eddfcc 100644 --- a/testapi/opnfv_testapi/models/pod_models.py +++ b/testapi/opnfv_testapi/models/pod_models.py @@ -18,7 +18,7 @@ from opnfv_testapi.tornado_swagger import swagger @swagger.model() class PodCreateRequest(base_models.ModelBase): - def __init__(self, name, mode='', details='', role=""): + def __init__(self, name='', mode='', details='', role=""): self.name = name self.mode = mode self.details = details @@ -26,17 +26,12 @@ class PodCreateRequest(base_models.ModelBase): @swagger.model() -class Pod(base_models.ModelBase): - def __init__(self, - name='', mode='', details='', - role="", _id='', create_date='', owner=''): - self.name = name - self.mode = mode - self.details = details - self.role = role - self._id = _id - self.creation_date = create_date - self.owner = owner +class Pod(PodCreateRequest): + def __init__(self, **kwargs): + self._id = kwargs.pop('_id', '') + self.creation_date = kwargs.pop('creation_date', '') + self.owner = kwargs.pop('owner', '') + super(Pod, self).__init__(**kwargs) @swagger.model() diff --git a/testapi/opnfv_testapi/models/result_models.py b/testapi/opnfv_testapi/models/result_models.py index 97fda08..1dbe729 100644 --- a/testapi/opnfv_testapi/models/result_models.py +++ b/testapi/opnfv_testapi/models/result_models.py @@ -31,6 +31,14 @@ class TI(base_models.ModelBase): self.current = current self.histories = list() + def __eq__(self, other): + return (self.current == other.current and self._histories_eq(other)) + + def _histories_eq(self, other): + hs_equal = all(self.histories[i] == other.histories[i] + for i in range(len(self.histories))) + return len(self.histories) == len(other.histories) and hs_equal + @staticmethod def attr_parser(): return {'histories': TIHistory} @@ -72,6 +80,16 @@ class ResultCreateRequest(base_models.ModelBase): self.public = public self.trust_indicator = trust_indicator if trust_indicator else TI(0) + def __eq__(self, other): + simple_equal = all(getattr(self, k) == getattr(other, k) + for k in self.format().keys() + if k not in ['_id', 'trust_indicator']) + return simple_equal and self.trust_indicator == other.trust_indicator + + @staticmethod + def attr_parser(): + return {'trust_indicator': TI} + @swagger.model() class ResultUpdateRequest(base_models.ModelBase): @@ -84,35 +102,14 @@ class ResultUpdateRequest(base_models.ModelBase): @swagger.model() -class TestResult(base_models.ModelBase): +class TestResult(ResultCreateRequest): """ @property trust_indicator: used for long duration test case @ptype trust_indicator: L{TI} """ - def __init__(self, _id=None, case_name=None, project_name=None, - pod_name=None, installer=None, version=None, - start_date=None, stop_date=None, details=None, - build_tag=None, scenario=None, criteria=None, - user=None, public="true", trust_indicator=None): + def __init__(self, _id=None, **kwargs): + super(TestResult, self).__init__(**kwargs) self._id = _id - self.case_name = case_name - self.project_name = project_name - self.pod_name = pod_name - self.installer = installer - self.version = version - self.start_date = start_date - self.stop_date = stop_date - self.details = details - self.build_tag = build_tag - self.scenario = scenario - self.criteria = criteria - self.user = user - self.public = public - self.trust_indicator = trust_indicator - - @staticmethod - def attr_parser(): - return {'trust_indicator': TI} @swagger.model() diff --git a/testapi/opnfv_testapi/models/testcase_models.py b/testapi/opnfv_testapi/models/testcase_models.py index d1b8877..96195b2 100644 --- a/testapi/opnfv_testapi/models/testcase_models.py +++ b/testapi/opnfv_testapi/models/testcase_models.py @@ -12,10 +12,20 @@ from opnfv_testapi.tornado_swagger import swagger @swagger.model() class TestcaseCreateRequest(base_models.ModelBase): - def __init__(self, name, url=None, description=None, - catalog_description=None, tier=None, ci_loop=None, - criteria=None, blocking=None, dependencies=None, run=None, - domains=None, tags=None, version=None): + def __init__(self, name=None, + url=None, + description=None, + catalog_description=None, + tier=None, + ci_loop=None, + criteria=None, + blocking=None, + dependencies=None, + run=None, + domains=None, + tags=None, + version=None, + trust='Silver'): self.name = name self.url = url self.description = description @@ -29,56 +39,23 @@ class TestcaseCreateRequest(base_models.ModelBase): self.domains = domains self.tags = tags self.version = version - self.trust = "Silver" + self.trust = trust @swagger.model() -class TestcaseUpdateRequest(base_models.ModelBase): - def __init__(self, name=None, description=None, project_name=None, - catalog_description=None, tier=None, ci_loop=None, - criteria=None, blocking=None, dependencies=None, run=None, - domains=None, tags=None, version=None, trust=None): - self.name = name - self.description = description - self.catalog_description = catalog_description - self.project_name = project_name - self.tier = tier - self.ci_loop = ci_loop - self.criteria = criteria - self.blocking = blocking - self.dependencies = dependencies - self.run = run - self.domains = domains - self.tags = tags - self.version = version - self.trust = trust +class TestcaseUpdateRequest(TestcaseCreateRequest): + def __init__(self, **kwargs): + self.project_name = kwargs.pop('project_name', '') + super(TestcaseUpdateRequest, self).__init__(**kwargs) @swagger.model() -class Testcase(base_models.ModelBase): - def __init__(self, _id=None, name=None, project_name=None, - description=None, url=None, creation_date=None, - catalog_description=None, tier=None, ci_loop=None, - criteria=None, blocking=None, dependencies=None, run=None, - domains=None, tags=None, version=None, - trust=None): - self._id = None - self.name = None - self.project_name = None - self.description = None - self.catalog_description = None - self.url = None - self.creation_date = None - self.tier = None - self.ci_loop = None - self.criteria = None - self.blocking = None - self.dependencies = None - self.run = None - self.domains = None - self.tags = None - self.version = None - self.trust = None +class Testcase(TestcaseCreateRequest): + def __init__(self, **kwargs): + self._id = kwargs.pop('_id', '') + self.project_name = kwargs.pop('project_name', '') + self.creation_date = kwargs.pop('creation_date', '') + super(Testcase, self).__init__(**kwargs) @swagger.model() diff --git a/testapi/opnfv_testapi/router/url_mappings.py b/testapi/opnfv_testapi/router/url_mappings.py index 349d557..a857725 100644 --- a/testapi/opnfv_testapi/router/url_mappings.py +++ b/testapi/opnfv_testapi/router/url_mappings.py @@ -10,6 +10,7 @@ import tornado.web from opnfv_testapi.common.config import CONF from opnfv_testapi.handlers import base_handlers +from opnfv_testapi.handlers import deploy_result_handlers as deploy_handlers from opnfv_testapi.handlers import pod_handlers from opnfv_testapi.handlers import project_handlers from opnfv_testapi.handlers import result_handlers @@ -50,6 +51,7 @@ mappings = [ (r"/api/v1/results", result_handlers.ResultsCLHandler), (r'/api/v1/results/upload', result_handlers.ResultsUploadHandler), (r"/api/v1/results/([^/]+)", result_handlers.ResultsGURHandler), + (r"/api/v1/deployresults", deploy_handlers.DeployResultsHandler), # scenarios (r"/api/v1/scenarios", scenario_handlers.ScenariosCLHandler), diff --git a/testapi/opnfv_testapi/tests/UI/e2e/homeControllerSpec.js b/testapi/opnfv_testapi/tests/UI/e2e/homeControllerSpec.js new file mode 100644 index 0000000..57794a6 --- /dev/null +++ b/testapi/opnfv_testapi/tests/UI/e2e/homeControllerSpec.js @@ -0,0 +1,56 @@ +'use strict'; + +var mock = require('protractor-http-mock'); +var baseURL = "http://localhost:8000" +describe('testing the home page for anonymous user', function () { + + it( 'should navigate to pods link ', function() { + browser.get(baseURL); + var signOut = element(by.linkText('Sign In / Sign Up')) + expect(signOut.isDisplayed()).toBe(true); + }); +}); + +describe('testing the home page for user', function () { + beforeEach(function(){ + mock([{ + request: { + path: '/api/v1/pods', + method: 'GET' + }, + response: { + data: { + pods: [{role: "community-ci", name: "test", owner: "testUser", + details: "DemoDetails", mode: "metal", _id: "59f02f099a07c84bfc5c7aed", + creation_date: "2017-10-25 11:58:25.926168"}] + } + } + }, + { + request: { + path: '/api/v1/profile', + method: 'GET' + }, + response: { + data: { + "fullname": "Test User", "_id": "79f82eey9a00c84bfhc7aed", + "user": "testUser", "groups": ["opnfv-testapi-users", + "opnfv-gerrit-functest-submitters"], "email": "testuser@test.com" + } + } + }]) + }); + + afterEach(function(){ + mock.teardown(); + }); + + it( 'should show the profile page', function() { + browser.get(baseURL); + var profile = element(by.linkText('Profile')) + expect(profile.isDisplayed()).toBe(true); + profile.click() + var EC = browser.ExpectedConditions; + browser.wait(EC.urlContains(baseURL+ '/#/profile'), 10000); + }); +}); diff --git a/testapi/opnfv_testapi/tests/UI/e2e/podsControllerSpec.js b/testapi/opnfv_testapi/tests/UI/e2e/podsControllerSpec.js index c3961ab..97e61ad 100644 --- a/testapi/opnfv_testapi/tests/UI/e2e/podsControllerSpec.js +++ b/testapi/opnfv_testapi/tests/UI/e2e/podsControllerSpec.js @@ -17,7 +17,24 @@ describe('testing the Pods page for anonymous user', function () { creation_date: "2017-10-25 11:58:25.926168"}] } } - }]); + }, + { + request: { + path: '/api/v1/pods', + method: 'GET', + queryString: { + name: 'test' + } + }, + response: { + data: { + pods: [{role: "community-ci", name: "test", owner: "testUser", + details: "DemoDetails", mode: "metal", _id: "59f02f099a07c84bfc5c7aed", + creation_date: "2017-10-25 11:58:25.926168"}] + } + } + } + ]); }); afterEach(function(){ @@ -42,81 +59,249 @@ describe('testing the Pods page for anonymous user', function () { expect(buttonFilter.isDisplayed()).toBe(true) }); - it('clear button is visible for anonymous user', function () { - var buttonClear = element(by.buttonText('Clear')); - expect(buttonClear.isDisplayed()).toBe(true) + it('Delete button is visible for anonymous user', function () { + var buttonDelete = element(by.buttonText('Delete')); + expect(buttonDelete.isDisplayed()).toBeFalsy(); }); - it('Show results when click filter button', function () { + it('Show results', function () { + var row = element.all(by.repeater('(index, pod) in ctrl.data.pods')).first(); + var cells = row.all(by.tagName('td')); + expect(cells.get(1).getText()).toContain("test"); + }); + + it('Show relevant results to the filter', function () { + var filter = element(by.model('ctrl.filterText')); + filter.sendKeys('test'); var buttonFilter = element(by.buttonText('Filter')); - buttonFilter.click(); - var pod = element(by.css('.show-pod')); - expect(pod.isPresent()).toBe(true); + var row = element.all(by.repeater('(index, pod) in ctrl.data.pods')).first(); + var cells = row.all(by.tagName('td')); + expect(cells.get(1).getText()).toContain("test"); }); - it('Show results when click clear button', function () { + it('delete Operation is not visible for user ', function () { browser.get(baseURL+'#/pods'); - var buttonClear = element(by.buttonText('Clear')); - buttonClear.click(); - var pod = element(by.css('.show-pod')); - expect(pod.isPresent()).toBe(true); + var deleteOperation = element(by.css('a[title=Delete]')); + expect(deleteOperation.isDisplayed()).toBeFalsy(); }); - it('If details is not shown then show details when click the link',function() { - expect(element(by.css('.show-pod.hidden')).isPresent()).toBe(true); - var podslink = element(by.linkText('test')).click(); - expect(element(by.css('.show-pod.hidden')).isPresent()).toBe(false); - }); - it('If details is shown then hide details when click the link',function() { - expect(element(by.css('.show-pod.hidden')).isPresent()).toBe(false); - var podslink = element(by.linkText('test')).click(); - expect(element(by.css('.show-pod.hidden')).isPresent()).toBe(true); +}); + +describe('testing the Pods page for authorized user', function () { + + beforeEach(function(){ + mock([{ + request: { + path: '/api/v1/pods', + method: 'GET' + }, + response: { + data: { + pods: [{role: "community-ci", name: "test", owner: "testUser", + details: "DemoDetails", mode: "metal", _id: "59f02f099a07c84bfc5c7aed", + creation_date: "2017-10-25 11:58:25.926168"}] + } + } + }, + { + request: { + path: '/api/v1/profile', + method: 'GET' + }, + response: { + data: { + "fullname": "Test User", "_id": "79f82eey9a00c84bfhc7aed", + "user": "testUser", "groups": ["opnfv-testapi-users", + "opnfv-gerrit-functest-submitters"], "email": "testuser@test.com" + } + } + }, + { + request: { + path: '/api/v1/pods', + method: 'GET', + queryString: { + name: 'test' + } + }, + response: { + data: { + pods: [{role: "community-ci", name: "test", owner: "testUser", + details: "DemoDetails", mode: "metal", _id: "59f02f099a07c84bfc5c7aed", + creation_date: "2017-10-25 11:58:25.926168"}] + } + } + }, + { + request: { + path: '/api/v1/pods/test', + method: 'DELETE' + }, + response: { + data: { + href: baseURL+"/api/v1/pods/test" + } + } + }, + { + request: { + path: '/api/v1/pods/test1', + method: 'DELETE' + }, + response: { + data: { + href: baseURL+"/api/v1/pods/test1" + } + } + }, + { + request: { + path: '/api/v1/pods', + method: 'POST' + }, + response: { + data: { + href: baseURL+"/api/v1/pods/test1" + } + } + }, + { + request: { + path: '/api/v1/pods/test', + method: 'GET' + }, + response: { + data: {role: "community-ci", name: "test", owner: "testUser", + details: "DemoDetails", mode: "metal", _id: "59f02f099a07c84bfc5c7aed", + creation_date: "2017-10-25 11:58:25.926168"} + } + } + ]); }); - it('If backend is not responding then show error when click filter button', function () { - browser.get(baseURL + '/#/pods'); + afterEach(function(){ mock.teardown(); + }); + + it( 'should navigate to pods link ', function() { + browser.get(baseURL); + var podslink = element(by.linkText('Pods')).click(); + var EC = browser.ExpectedConditions; + browser.wait(EC.urlContains(baseURL+ '/#/pods'), 10000); + }); + + it('create button is not visible for user', function () { + browser.get(baseURL+'#/pods'); + var buttonCreate = element(by.buttonText('Create')); + expect(buttonCreate.isDisplayed()).toBe(true); + }); + + it('filter button is visible for user', function () { var buttonFilter = element(by.buttonText('Filter')); - buttonFilter.click().then(function(){ - expect(element(by.css('.alert.alert-danger.ng-binding.ng-scope')) - .isDisplayed()).toBe(true); - }); + expect(buttonFilter.isDisplayed()).toBe(true) }); -}); + it('Delete button is visible for user', function () { + var buttonDelete = element(by.buttonText('Delete')); + expect(buttonDelete.isDisplayed()).toBe(true) + }); -describe('testing the Pods page for authorized user', function () { + it('Show results', function () { + var row = element.all(by.repeater('(index, pod) in ctrl.data.pods')).first(); + var cells = row.all(by.tagName('td')); + expect(cells.get(1).getText()).toContain("test"); + }); - beforeEach(function(){ - mock([ - { + it('Show relevant results to the filter', function () { + var filter = element(by.model('ctrl.filterText')); + filter.sendKeys('test'); + var buttonFilter = element(by.buttonText('Filter')); + var row = element.all(by.repeater('(index, pod) in ctrl.data.pods')).first(); + var cells = row.all(by.tagName('td')); + expect(cells.get(1).getText()).toContain("test"); + }); + + it('delete Operation is visible for user ', function () { + browser.get(baseURL+'#/pods'); + var deleteOperation = element(by.css('a[title=Delete]')); + expect(deleteOperation.isDisplayed()).toBe(true); + }); + + it('Batch Delete the pods ', function () { + browser.get(baseURL+"#/pods"); + var checkBox = element(by.model('ctrl.checkBox[index]')); + checkBox.click(); + var buttonDelete = element(by.buttonText('Delete'));; + buttonDelete.click(); + var buttonOK = element(by.buttonText('Ok')); + buttonOK.click(); + expect(element(by.cssContainingText(".alert","Delete Success")) + .isDisplayed()).toBe(true); + }); + + it('Delete the pods ', function () { + browser.get(baseURL+"#/pods"); + var deleteOperation = element(by.css('a[title=Delete]')); + deleteOperation.click(); + var buttonOK = element(by.buttonText('Ok')); + buttonOK.click(); + expect(element(by.cssContainingText(".alert","Delete Success")) + .isDisplayed()).toBe(true); + }); + + it('Create the pod', function () { + browser.get(baseURL+"#/pods"); + var buttonCreate = element(by.buttonText('Create')); + buttonCreate.click(); + var name = element(by.model('PodModalCtrl.pod.name')); + var EC = browser.ExpectedConditions; + browser.wait(EC.visibilityOf(name), 5000); + name.sendKeys('test1'); + var buttonOK = element(by.buttonText('Ok')); + buttonOK.click(); + expect(element(by.cssContainingText(".alert","Create Success")) + .isDisplayed()).toBe(true); + }); + + it('Showing error when creating with a empty name ', function () { + browser.get(baseURL+"#/pods"); + var buttonCreate = element(by.buttonText('Create')); + buttonCreate.click(); + var name = element(by.model('PodModalCtrl.pod.name')); + var EC = browser.ExpectedConditions; + browser.wait(EC.visibilityOf(name), 5000); + var buttonOK = element(by.buttonText('Ok')); + buttonOK.click() + expect(element(by.cssContainingText(".alert","Name is missing.")) + .isDisplayed()).toBe(true); + }); + + it('cancel the delete confimation modal of the pod ', function () { + browser.get(baseURL+"#/pods"); + var deleteOperation = element(by.css('a[title=Delete]')); + deleteOperation.click(); + var buttonCancel = element(by.buttonText('Cancel')); + buttonCancel.click(); + expect(buttonCancel.isPresent()).toBe(false); + }); + + it('Delete the pods which do not exist ', function () { + mock.teardown(); + mock([{ request: { - path: '/api/v1/pods', - method: 'POST' + path: '/api/v1/pods', + method: 'GET' }, response: { data: { - href: baseURL+"/api/v1/pods/test" + pods: [{role: "community-ci", name: "test1", owner: "testUser", + details: "DemoDetails", mode: "metal", _id: "59f02f099a07c84bfc5c7aed", + creation_date: "2017-10-25 11:58:25.926168"}] } - } - }, - { - request: { - path: '/api/v1/pods', - method: 'POST', - data: { - name: 'test1', - details : 'DemoDetails', - role : 'community-ci', - mode : 'metal' - } - }, - response: { - status : 403 - } - }, - { + } + }, + { request: { path: '/api/v1/profile', method: 'GET' @@ -127,57 +312,48 @@ describe('testing the Pods page for authorized user', function () { "user": "testUser", "groups": ["opnfv-testapi-users", "opnfv-gerrit-functest-submitters"], "email": "testuser@test.com" } + } + }, + { + request: { + path: '/api/v1/pods/test1', + method: 'DELETE' + }, + response: { + status : 403, + data : 'pods do not exist' } } ]); + browser.get(baseURL+"#/pods"); + var deleteOperation = element(by.css('a[title=Delete]')); + deleteOperation.click(); + var buttonOK = element(by.buttonText('Ok')); + buttonOK.click(); + expect(element(by.css(".alert.alert-danger")) + .isDisplayed()).toBe(true); }); - afterEach(function(){ - mock.teardown(); - }); - - it('create button is visible for authorized user', function () { - browser.get(baseURL + '/#/pods'); - var buttonCreate = element(by.buttonText('Create')); - expect(buttonCreate.isDisplayed()).toBe(true); + it('view the test case ', function () { + browser.get(baseURL+"#/pods"); + var viewOperation = element(by.css('a[class=text-info]')); + viewOperation.click(); + var EC = browser.ExpectedConditions; + browser.wait(EC.urlContains('#/pods/test'), 10000); }); - it('Do not show error if input is acceptable', function () { - var name = element(by.model('ctrl.name')); - var details = element(by.model('ctrl.details')); - name.sendKeys('test'); - details.sendKeys('DemoDetails'); - var buttonCreate = element(by.buttonText('Create')); - buttonCreate.click().then(function(){ - expect(element(by.css('.alert.alert-danger.ng-binding.ng-scope')) - .isDisplayed()).toBe(false); - }); - }); - - it('Show error when user click the create button with a empty name', function () { - browser.get(baseURL+ '/#/pods'); - var details = element(by.model('ctrl.details')); - details.sendKeys('DemoDetails'); - var buttonCreate = element(by.buttonText('Create')); - buttonCreate.click(); - expect(element(by.cssContainingText(".alert","Name is missing.")).isDisplayed()).toBe(true); - }); - - it('Show error when user click the create button with an already existing name', function () { - browser.get(baseURL+ '/#/pods'); - var name = element(by.model('ctrl.name')); - var details = element(by.model('ctrl.details')); - name.sendKeys('test1'); - details.sendKeys('DemoDetails'); - var buttonCreate = element(by.buttonText('Create')); - buttonCreate.click(); - expect(element(by.cssContainingText(".alert","Error creating the new pod from server: undefined")).isDisplayed()).toBe(true); - }); - - it('If backend is not responding then show error when user click the create button',function(){ + it('Show error if server is not responding', function () { mock.teardown(); - mock([ - { + mock([{ + request: { + path: '/api/v1/pods', + method: 'GET' + }, + response: { + status : 404 + } + }, + { request: { path: '/api/v1/profile', method: 'GET' @@ -185,21 +361,15 @@ describe('testing the Pods page for authorized user', function () { response: { data: { "fullname": "Test User", "_id": "79f82eey9a00c84bfhc7aed", - "user": "testUser", "groups": ["opnfv-testapi-users"], - "email": "testuser@test.com" + "user": "testUser", "groups": ["opnfv-testapi-users", + "opnfv-gerrit-functest-submitters"], "email": "testuser@test.com" } - } } + }, ]); - browser.get(baseURL+ '/#/pods'); - var name = element(by.model('ctrl.name')); - var details = element(by.model('ctrl.details')); - name.sendKeys('test'); - details.sendKeys('DemoDetails'); - var buttonCreate = element(by.buttonText('Create')); - buttonCreate.click().then(function(){ - expect(element(by.css('.alert.alert-danger.ng-binding')) - .isDisplayed()).toBe(true); - }); + browser.get(baseURL+"#/pods"); + expect(element(by.css(".alert.alert-danger")) + .isDisplayed()).toBe(true); }); + });
\ No newline at end of file diff --git a/testapi/opnfv_testapi/tests/UI/e2e/projectControllerSpec.js b/testapi/opnfv_testapi/tests/UI/e2e/projectControllerSpec.js deleted file mode 100644 index 475e037..0000000 --- a/testapi/opnfv_testapi/tests/UI/e2e/projectControllerSpec.js +++ /dev/null @@ -1,354 +0,0 @@ -'use strict'; - -var mock = require('protractor-http-mock'); -var baseURL = "http://localhost:8000/#/" - -describe('testing the Project Link for anonymous user', function () { - beforeEach(function(){ - mock([ - { - request: { - path: '/api/v1/projects/testproject', - method: 'GET' - }, - response: { - data: { - "owner": "thuva4", - "_id": "5a0c022f9a07c846d3c2cc94", - "creation_date": "2017-11-15 14:30:31.200259", - "description": "dsfsd", - "name": "testproject" - } - } - } - ]); - }); - - afterEach(function(){ - mock.teardown(); - }); - - it( 'navigate to the project page', function() { - browser.get(baseURL+"projects/testproject"); - var EC = browser.ExpectedConditions; - browser.wait(EC.urlContains(baseURL+ 'projects/testproject'), 10000); - }); - - it('show the project details for anonymous user ', function(){ - var table = $$('.projects-table.ng-scope tr'); - var projectDetailsLable = ['Name','Description','Creation date'] - var projectDetails = ['testproject', 'dsfsd','2017-11-15 14:30:31.200259'] - table.each(function(row,index) { - var rowElems = row.$$('td'); - expect(rowElems.count()).toBe(2); - expect(rowElems.get(0).getText()).toMatch(projectDetailsLable[index]); - expect(rowElems.get(1).getText()).toMatch(projectDetails[index]); - }); - }); - - it('should not show the update & delete button', function(){ - var buttonUpdate = element(by.buttonText('Update Project')); - var buttonDelete = element(by.buttonText('Delete Project')); - expect(buttonUpdate.isDisplayed()).toBeFalsy(); - expect(buttonDelete.isDisplayed()).toBeFalsy(); - }); - -}); - - -describe('testing the Project Link for authorized user(not a submitter)', function () { - beforeEach(function(){ - mock([ - { - request: { - path: '/api/v1/projects/testproject', - method: 'GET' - }, - response: { - data: { - "owner": "thuva4", - "_id": "5a0c022f9a07c846d3c2cc94", - "creation_date": "2017-11-15 14:30:31.200259", - "description": "dsfsd", - "name": "testproject" - } - } - }, - { - request: { - path: '/api/v1/profile', - method: 'GET' - }, - response: { - data: { - "fullname": "Test User", "_id": "79f82eey9a00c84bfhc7aed", - "user": "testUser", "groups": ["opnfv-testapi-users"], - "email": "testuser@test.com" - } - } - } - ]); - }); - - afterEach(function(){ - mock.teardown(); - }); - - it( 'navigate to the project page', function() { - browser.get(baseURL+"projects/testproject"); - var EC = browser.ExpectedConditions; - browser.wait(EC.urlContains(baseURL+ 'projects/testproject'), 10000); - }); - - it('show the project details for user ', function(){ - var table = $$('.projects-table.ng-scope tr'); - var projectDetailsLable = ['Name','Description','Creation date'] - var projectDetails = ['testproject', 'dsfsd','2017-11-15 14:30:31.200259'] - table.each(function(row,index) { - var rowElems = row.$$('td'); - expect(rowElems.count()).toBe(2); - expect(rowElems.get(0).getText()).toMatch(projectDetailsLable[index]); - expect(rowElems.get(1).getText()).toMatch(projectDetails[index]); - }); - }); - - it('should not show the update & delete button', function(){ - var buttonUpdate = element(by.buttonText('Update Project')); - var buttonDelete = element(by.buttonText('Delete Project')); - expect(buttonUpdate.isDisplayed()).toBeFalsy(); - expect(buttonDelete.isDisplayed()).toBeFalsy(); - }); - -}); - -describe('testing the Project Link for authorized user(a submitter)', function () { - beforeEach(function(){ - mock([ - { - request: { - path: '/api/v1/projects/testproject', - method: 'GET' - }, - response: { - data: { - "owner": "thuva4", - "_id": "5a0c022f9a07c846d3c2cc94", - "creation_date": "2017-11-15 14:30:31.200259", - "description": "dsfsd", - "name": "testproject" - } - } - }, - { - request: { - path: '/api/v1/projects/testproject1', - method: 'GET' - }, - response: { - data: { - "owner": "thuva4", - "_id": "5a0c022f9a07c846d3c2cc94", - "creation_date": "2017-11-15 14:30:31.200259", - "description": "dsfsd", - "name": "testproject1" - } - } - }, - { - request: { - path: '/api/v1/projects', - method: 'GET' - }, - response: { - data: { - "projects": [ - { - "owner": "thuva4", - "_id": "5a0c022f9a07c846d3c2cc94", - "creation_date": "2017-11-15 14:30:31.200259", - "description": "dsfsd", - "name": "testproject" - } - ] - } - } - }, - { - request: { - path: '/api/v1/projects/testproject', - method: 'DELETE' - }, - response: { - status : 200 - } - }, - { - request: { - path: '/api/v1/projects/testproject1', - method: 'DELETE' - }, - response: { - status : 403 - } - }, - { - request: { - path: '/api/v1/projects/testproject', - method: 'PUT', - data: { - name: 'testProject2', - description : 'demoDescription', - } - }, - response: { - status : 200, - data : { - "owner": "thuva4", - "_id": "5a0c022f9a07c846d3c2cc94", - "creation_date": "2017-11-15 14:30:31.200259", - "description": "dsfsd", - "name": "testproject2" - } - } - }, - { - request: { - path: '/api/v1/projects/testproject', - method: 'PUT', - data: { - name: 'testProject1', - description : 'demoDescription', - } - }, - response: { - status : 403 - } - }, - { - request: { - path: '/api/v1/profile', - method: 'GET' - }, - response: { - data: { - "fullname": "Test User", "_id": "79f82eey9a00c84bfhc7aed", - "user": "testUser", "groups": ["opnfv-testapi-users", - "opnfv-gerrit-testProject-submitters", - "opnfv-gerrit-testProject2-submitters" ], - "email": "testuser@test.com" - } - } - }, - ]); - }); - - afterEach(function(){ - mock.teardown(); - }); - - it( 'navigate to the project page', function() { - browser.get(baseURL+"projects/testproject"); - var EC = browser.ExpectedConditions; - browser.wait(EC.urlContains(baseURL+ 'projects/testproject'), 10000); - }); - - it('show the project details for user ', function(){ - var table = $$('.projects-table.ng-scope tr'); - var projectDetailsLable = ['Name','Description','Creation date'] - var projectDetails = ['testproject', 'dsfsd','2017-11-15 14:30:31.200259'] - table.each(function(row,index) { - var rowElems = row.$$('td'); - expect(rowElems.count()).toBe(2); - expect(rowElems.get(0).getText()).toMatch(projectDetailsLable[index]); - expect(rowElems.get(1).getText()).toMatch(projectDetails[index]); - }); - }); - - it('should show the update & delete button', function(){ - var buttonUpdate = element(by.buttonText('Update Project')); - var buttonDelete = element(by.buttonText('Delete Project')); - expect(buttonUpdate.isDisplayed()).toBe(true); - expect(buttonDelete.isDisplayed()).toBe(true); - }); - - it('show the update modal when user clicks the update button', function(){ - browser.get(baseURL+"projects/testproject"); - var buttonDelete = element(by.buttonText('Update Project')).click(); - var EC = protractor.ExpectedConditions; - var elm = element(by.css(".modal-body")); - browser.wait(EC.textToBePresentInElement(elm, "Update"), 5000); - expect(elm.isDisplayed()).toBe(true); - var buttonCancel = element(by.buttonText('Cancel')).click(); - expect(elm.isPresent()).toEqual(false); - }); - - it('send a update request to server and show success when we click ok', function(){ - browser.get(baseURL+"projects/testproject"); - var buttonUpdate = element(by.buttonText('Update Project')).click(); - var EC = protractor.ExpectedConditions; - var elm = element(by.css(".modal-body")); - browser.wait(EC.textToBePresentInElement(elm, "Update"), 5000); - expect(elm.isDisplayed()).toBe(true); - var name = element(by.model('updateModal.name')); - var description = element(by.model('updateModal.description')); - name.click().clear().sendKeys('testProject2'); - description.click().clear().sendKeys('demoDescription'); - var buttonOk = element(by.buttonText('Ok')).click(); - expect(element(by.cssContainingText(".alert.alert-success", - "Update Success")) - .isDisplayed()).toBe(true); - }); - - it('show error when server send a error response when we click ok', function(){ - browser.get(baseURL+"projects/testproject"); - var buttonUpdate = element(by.buttonText('Update Project')).click(); - var EC = protractor.ExpectedConditions; - var elm = element(by.css(".modal-body")); - browser.wait(EC.textToBePresentInElement(elm, "Update"), 5000); - expect(elm.isDisplayed()).toBe(true); - var name = element(by.model('updateModal.name')); - var description = element(by.model('updateModal.description')); - name.click().clear().sendKeys('testProject1'); - description.click().clear().sendKeys('demoDescription'); - var buttonOk = element(by.buttonText('Ok')).click(); - expect(element(by.cssContainingText(".alert", - "Error updating the existing Project from server: undefined")) - .isDisplayed()).toBe(true); - }); - - it('show the confirm modal when user clicks the delete button', function(){ - var buttonDelete = element(by.buttonText('Delete Project')).click(); - var EC = protractor.ExpectedConditions; - var elm = element(by.css(".modal-body")); - browser.wait(EC.textToBePresentInElement(elm, "You are about to delete."), 5000); - expect(elm.isDisplayed()).toBe(true); - var buttonCancel = element(by.buttonText('Cancel')).click(); - expect(elm.isPresent()).toEqual(false); - }); - - it('send a delete request to server when we click ok', function(){ - var buttonDelete = element(by.buttonText('Delete Project')).click(); - var EC = protractor.ExpectedConditions; - var elm = element(by.css(".modal-body")); - browser.wait(EC.textToBePresentInElement(elm, "You are about to delete."), 5000); - expect(elm.isDisplayed()).toBe(true); - var buttonCancel = element(by.buttonText('Ok')).click(); - browser.wait(EC.urlContains(baseURL+ 'projects'), 10000); - }); - - it('show the error message when we click ok', function(){ - browser.get(baseURL+"projects/testproject1"); - var buttonDelete = element(by.buttonText('Delete Project')).click(); - var EC = protractor.ExpectedConditions; - var elm = element(by.css(".modal-body")); - browser.wait(EC.textToBePresentInElement(elm, "You are about to delete."), 5000); - expect(elm.isDisplayed()).toBe(true); - var buttonCancel = element(by.buttonText('Ok')).click(); - // browser.wait(EC.urlContains(baseURL+ 'projects'), 10000); - expect(element(by.cssContainingText(".alert", - "Error deleting project from server: undefined")) - .isDisplayed()).toBe(true); - // browser.pause(); - }); - -});
\ No newline at end of file diff --git a/testapi/opnfv_testapi/tests/UI/e2e/projectsControllerSpec.js b/testapi/opnfv_testapi/tests/UI/e2e/projectsControllerSpec.js index 64a5aeb..8b908c9 100644 --- a/testapi/opnfv_testapi/tests/UI/e2e/projectsControllerSpec.js +++ b/testapi/opnfv_testapi/tests/UI/e2e/projectsControllerSpec.js @@ -51,18 +51,30 @@ describe('testing the Projects Link for anonymous user', function () { expect(buttonCreate.isDisplayed()).toBeFalsy(); }); - it('Show projects list when user comes to the projects page', function () { - var firstBookName = element(by.repeater('(index, project) in ctrl.data.projects'). - row(0).column('{{project.name}}')); - expect(firstBookName).toBeDefined(); + it('Delete button is not visible for anonymous user ', function () { + browser.get(baseURL+'#/projects'); + var buttonCreate = element(by.buttonText('Create')); + expect(buttonCreate.isDisplayed()).toBeFalsy(); }); - it('redirect to project page when user clicks a project',function(){ - var projectlink = element(by.linkText('testproject')).click(); - var EC = browser.ExpectedConditions; - browser.wait(EC.urlContains(baseURL+ '/#/projects/testproject'), 10000); + it('Show projects list when anonymous user comes to the projects page', function () { + var row = element.all(by.repeater('(index, project) in ctrl.data.projects')).first(); + var cells = row.all(by.tagName('td')); + expect(cells.get(1).getText()).toContain("testproject"); }); + // it('redirect to project page when user clicks a project',function(){ + // var projectlink = element(by.linkText('testproject')).click(); + // var EC = browser.ExpectedConditions; + // browser.wait(EC.urlContains(baseURL+ '/#/projects/testproject'), 10000); + // }); + + it('delete Operation is not visible for anonymous user ', function () { + browser.get(baseURL+'#/projects'); + var deleteOperation = element(by.css('a[title=Delete]')); + expect(deleteOperation.isDisplayed()).toBeFalsy(); + }); + }); describe('testing the Project Link for user who is not in submitter group', function () { @@ -70,6 +82,26 @@ describe('testing the Project Link for user who is not in submitter group', func mock([ { request: { + path: '/api/v1/projects', + method: 'GET', + queryString: { + name: 'test' + } + }, + response: { + data: { + "projects": [ + { + "_id": "5a0c1c9a9a07c846d3a7247b", + "creation_date": "2017-11-15 16:23:14.217093", + "description": "sdgfd", + "name": "test" + }] + } + } + }, + { + request: { path: '/api/v1/profile', method: 'GET' }, @@ -80,6 +112,25 @@ describe('testing the Project Link for user who is not in submitter group', func "email": "testuser@test.com" } } + }, + { + request: { + path: '/api/v1/projects', + method: 'GET' + }, + response: { + data: { + "projects": [ + { + "owner": "thuva4", + "_id": "5a0c022f9a07c846d3c2cc94", + "creation_date": "2017-11-15 14:30:31.200259", + "description": "dsfsd", + "name": "testproject" + } + ] + } + } } ]); }); @@ -106,6 +157,28 @@ describe('testing the Project Link for user who is not in submitter group', func var buttonCreate = element(by.buttonText('Create')); expect(buttonCreate.isDisplayed()).toBeFalsy(); }); + + it('Delete button is not visible for user ', function () { + browser.get(baseURL+'#/projects'); + var buttonCreate = element(by.buttonText('Create')); + expect(buttonCreate.isDisplayed()).toBeFalsy(); + }); + + it('delete Operation is not visible for user ', function () { + browser.get(baseURL+'#/projects'); + var deleteOperation = element(by.css('a[title=Delete]')); + expect(deleteOperation.isDisplayed()).toBeFalsy(); + }); + + it('Show relevant results to the filter', function () { + var filter = element(by.model('ctrl.filterText')); + filter.sendKeys('test'); + var buttonFilter = element(by.buttonText('Filter')); + buttonFilter.click() + var row = element.all(by.repeater('(index, project) in ctrl.data.projects')).first(); + var cells = row.all(by.tagName('td')); + expect(cells.get(1).getText()).toContain("test"); + }); }) describe('testing the Project Link for user who is in submitter group', function () { @@ -139,6 +212,28 @@ describe('testing the Project Link for user who is in submitter group', function }, { request: { + path: '/api/v1/projects/vsfv', + method: 'DELETE' + }, + response: { + data: { + href: baseURL+"/api/v1/projects/testProject1" + } + } + }, + { + request: { + path: '/api/v1/projects/vsfv', + method: 'PUT' + }, + response: { + data: { + href: baseURL+"/api/v1/projects/testProject1" + } + } + }, + { + request: { path: '/api/v1/projects', method: 'POST', data: { @@ -163,6 +258,23 @@ describe('testing the Project Link for user who is in submitter group', function status : 403, data : 'You do not have permission to perform this action' } + }, + { + request: { + path: '/api/v1/projects', + method: 'GET' + }, + response: { + data : { + "projects": [ + { + "_id": "5a0c1c9a9a07c846d3a7247b", + "creation_date": "2017-11-15 16:23:14.217093", + "description": "sdgfd", + "name": "vsfv" + }] + } + } } ]); }); @@ -190,53 +302,247 @@ describe('testing the Project Link for user who is in submitter group', function expect(buttonCreate.isDisplayed()).toBe(true); }); - it('Show error when user click the create button with a empty name', function () { - browser.get(baseURL+ '/#/projects'); - var description = element(by.model('ctrl.description')); - description.sendKeys('DemoDescription'); - var buttonCreate = element(by.buttonText('Create')); - buttonCreate.click(); - expect(element(by.cssContainingText(".alert","Name is missing.")) + it('Delete button is not visible for anonymous user ', function () { + browser.get(baseURL+'#/projects'); + var buttonCreate = element(by.buttonText('Create')); + expect(buttonCreate.isDisplayed()).toBe(true); + }); + + it('delete Operation is not visible for user ', function () { + browser.get(baseURL+'#/projects'); + var deleteOperation = element(by.css('a[title=Delete]')); + expect(deleteOperation.isDisplayed()).toBe(true); + }); + + it('Edit Operation is visible for user ', function () { + browser.get(baseURL+'#/projects'); + var editOperation = element(by.css('a[title=Edit]')); + expect(editOperation.isDisplayed()).toBe(true); + }); + + it('Create the Project', function () { + browser.get(baseURL+"#/projects"); + var buttonCreate = element(by.buttonText('Create')); + buttonCreate.click(); + var name = element(by.model('ProjectModalCtrl.project.name')); + var EC = browser.ExpectedConditions; + browser.wait(EC.visibilityOf(name), 5000); + name.sendKeys('testproject'); + var buttonOK = element(by.buttonText('Ok')); + buttonOK.click(); + expect(element(by.cssContainingText(".alert","Project is successfully created.")) .isDisplayed()).toBe(true); - }); + }); - it('Show error when user click the create button with an already existing name', function () { - browser.get(baseURL+ '/#/projects'); - var name = element(by.model('ctrl.name')); - var details = element(by.model('ctrl.description')); - name.sendKeys('testProject2'); - details.sendKeys('demoDescription'); - var buttonCreate = element(by.buttonText('Create')); - buttonCreate.click(); - expect(element(by.cssContainingText(".alert", - "Error creating the new Project from server:undefined")) + it('Show error if user doesnt have permission to Create the Project', function () { + browser.get(baseURL+"#/projects"); + var buttonCreate = element(by.buttonText('Create')); + buttonCreate.click(); + var name = element(by.model('ProjectModalCtrl.project.name')); + var EC = browser.ExpectedConditions; + browser.wait(EC.visibilityOf(name), 5000); + var description = element(by.model('ProjectModalCtrl.project.description')); + name.sendKeys('testProject2'); + description.sendKeys('demoDescription'); + var buttonOK = element(by.buttonText('Ok')); + buttonOK.click(); + expect(element(by.css(".alert.alert-danger")).isDisplayed()).toBe(true); + }); + + it('Showing error when creating with a empty name ', function () { + browser.get(baseURL+"#/projects"); + var buttonCreate = element(by.buttonText('Create')); + buttonCreate.click(); + var name = element(by.model('ProjectModalCtrl.project.name')); + var EC = browser.ExpectedConditions; + browser.wait(EC.visibilityOf(name), 5000); + var buttonOK = element(by.buttonText('Ok')); + buttonOK.click(); + expect(element(by.cssContainingText(".alert","Name is missing.")) .isDisplayed()).toBe(true); }); - it('Show error when user try to create a project which he is not belonged to ', function () { - browser.get(baseURL+ '/#/projects'); - var name = element(by.model('ctrl.name')); - var details = element(by.model('ctrl.description')); - name.sendKeys('testProject3'); - details.sendKeys('demoDescription'); - var buttonCreate = element(by.buttonText('Create')); + it('Show error when user click the create button with an already existing name', function () { + browser.get(baseURL+"#/projects"); + var buttonCreate = element(by.buttonText('Create')); buttonCreate.click(); - expect(element(by.cssContainingText(".alert", - 'Error creating the new Project from server:"You do not have permission to perform this action"')).isDisplayed()) - .toBe(true); + var name = element(by.model('ProjectModalCtrl.project.name')); + var EC = browser.ExpectedConditions; + browser.wait(EC.visibilityOf(name), 5000); + var description = element(by.model('ProjectModalCtrl.project.description')); + name.sendKeys('testProject3'); + description.sendKeys('demoDescription'); + var buttonOK = element(by.buttonText('Ok')); + buttonOK.click(); + expect(element(by.css(".alert.alert-danger")).isDisplayed()).toBe(true); }); - it('Do not show error if input is acceptable', function () { - var name = element(by.model('ctrl.name')); - var details = element(by.model('ctrl.description')); - name.sendKeys('testProject1'); - details.sendKeys('demoDescription'); - var buttonCreate = element(by.buttonText('Create')); - buttonCreate.click().then(function(){ - expect(element(by.cssContainingText(".alert", - "Create Success")) - .isDisplayed()).toBe(true); - }); + it('cancel the delete confimation modal of the project ', function () { + browser.get(baseURL+"#/projects"); + var deleteOperation = element(by.css('a[title=Delete]')); + deleteOperation.click(); + var buttonCancel = element(by.buttonText('Cancel')); + buttonCancel.click(); + expect(buttonCancel.isPresent()).toBe(false); + }); + + it('Delete the projects ', function () { + browser.get(baseURL+"#/projects"); + var deleteOperation = element(by.css('a[title=Delete]')); + deleteOperation.click(); + var buttonOK = element(by.buttonText('Ok')); + buttonOK.click(); + expect(element(by.cssContainingText(".alert","Projects is successfully deleted")) + .isDisplayed()).toBe(true); + }); + + it(' Show error if user doesnt has permission to delete the projects ', function () { + mock.teardown(); + mock([ + { + request: { + path: '/api/v1/profile', + method: 'GET' + }, + response: { + data: { + "fullname": "Test User", "_id": "79f82eey9a00c84bfhc7aed", + "user": "testUser", "groups": ["opnfv-testapi-users", + "opnfv-gerrit-testProject1-submitters", + "opnfv-gerrit-testProject2-submitters" ], + "email": "testuser@test.com" + } + } + }, + { + request: { + path: '/api/v1/projects/testproject3', + method: 'DELETE' + }, + response: { + status: 403 + } + }, + { + request: { + path: '/api/v1/projects', + method: 'GET' + }, + response: { + data : { + "projects": [ + { + "_id": "5a0c1c9a9a07c846d3a7247b", + "creation_date": "2017-11-15 16:23:14.217093", + "description": "sdgfd", + "name": "testproject3" + }] + } + } + } + ]); + browser.get(baseURL+"#/projects"); + var deleteOperation = element(by.css('a[title=Delete]')); + deleteOperation.click(); + var buttonOK = element(by.buttonText('Ok')); + buttonOK.click(); + expect(element(by.css(".alert.alert-danger")).isDisplayed()).toBe(true); + }); + + it('cancel the Edit modal of the Project ', function () { + browser.get(baseURL+"#/projects"); + var editOperation = element(by.css('a[title=Edit]')); + editOperation.click(); + var name = element(by.model('ProjectModalCtrl.project.name')); + var EC = browser.ExpectedConditions; + browser.wait(EC.visibilityOf(name), 5000); + name.sendKeys('test1'); + var buttonCancel = element(by.buttonText('Cancel')); + buttonCancel.click(); + expect(name.isPresent()).toBe(false); + }); + + it('Edit the Project ', function () { + browser.get(baseURL+"#/projects"); + var editOperation = element(by.css('a[title=Edit]')); + editOperation.click(); + var name = element(by.model('ProjectModalCtrl.project.name')); + var EC = browser.ExpectedConditions; + browser.wait(EC.visibilityOf(name), 5000); + name.sendKeys('test1'); + var buttonOK = element(by.buttonText('Ok')); + buttonOK.click() + expect(element(by.cssContainingText(".alert","Project is successfully updated.")) + .isDisplayed()).toBe(true); + }); + + it('Show error if user doesnt has permission to edit the projects ', function () { + mock.teardown(); + mock([ + { + request: { + path: '/api/v1/profile', + method: 'GET' + }, + response: { + data: { + "fullname": "Test User", "_id": "79f82eey9a00c84bfhc7aed", + "user": "testUser", "groups": ["opnfv-testapi-users", + "opnfv-gerrit-testProject1-submitters", + "opnfv-gerrit-testProject2-submitters" ], + "email": "testuser@test.com" + } + } + }, + { + request: { + path: '/api/v1/projects/testproject3', + method: 'PUT' + }, + response: { + status: 403 + } + }, + { + request: { + path: '/api/v1/projects', + method: 'GET' + }, + response: { + data : { + "projects": [ + { + "_id": "5a0c1c9a9a07c846d3a7247b", + "creation_date": "2017-11-15 16:23:14.217093", + "description": "sdgfd", + "name": "testproject3" + }] + } + } + } + ]); + browser.get(baseURL+"#/projects"); + var editOperation = element(by.css('a[title=Edit]')); + editOperation.click(); + var name = element(by.model('ProjectModalCtrl.project.name')); + var EC = browser.ExpectedConditions; + browser.wait(EC.visibilityOf(name), 5000); + name.sendKeys('test1'); + var buttonOK = element(by.buttonText('Ok')); + buttonOK.click() + expect(element(by.css(".alert.alert-danger")).isDisplayed()).toBe(true); + }); + + it('Batch Delete the projects ', function () { + browser.get(baseURL+"#/projects"); + var checkBox = element(by.model('ctrl.checkBox[index]')); + checkBox.click(); + var buttonDelete = element(by.buttonText('Delete'));; + buttonDelete.click(); + var buttonOK = element(by.buttonText('Ok')); + buttonOK.click(); + expect(element(by.cssContainingText(".alert","Projects is successfully deleted")) + .isDisplayed()).toBe(true); }); it('If backend is not responding then show error when user click the create button',function(){ @@ -258,13 +564,17 @@ describe('testing the Project Link for user who is in submitter group', function } } ]); - browser.get(baseURL+ '/#/projects'); - var name = element(by.model('ctrl.name')); - var details = element(by.model('ctrl.description')); - name.sendKeys('testProject1'); + browser.get(baseURL+"#/projects"); + var buttonCreate = element(by.buttonText('Create')); + buttonCreate.click(); + var name = element(by.model('ProjectModalCtrl.project.name')); + var EC = browser.ExpectedConditions; + browser.wait(EC.visibilityOf(name), 5000); + var details = element(by.model('ProjectModalCtrl.project.description')); + name.sendKeys('testproject'); details.sendKeys('demoDescription'); - var buttonCreate = element(by.buttonText('Create')); - buttonCreate.click().then(function(){ + var buttonOK = element(by.buttonText('Ok')); + buttonOK.click().then(function(){ expect(element(by.css(".alert.alert-danger")).isDisplayed()).toBe(true); }); }); diff --git a/testapi/opnfv_testapi/tests/UI/e2e/resultsControllerSpec.js b/testapi/opnfv_testapi/tests/UI/e2e/resultsControllerSpec.js new file mode 100644 index 0000000..d6dfa1c --- /dev/null +++ b/testapi/opnfv_testapi/tests/UI/e2e/resultsControllerSpec.js @@ -0,0 +1,381 @@ +'use strict'; + +var mock = require('protractor-http-mock'); +var baseURL = "http://localhost:8000/" + +describe('testing the result page for anonymous user', function () { + beforeEach(function(){ + mock([ + { + request: { + path: '/api/v1/results', + method: 'GET', + queryString: { + page: '1' + } + }, + response: { + data: { + "pagination": { + "current_page": 1, + "total_pages": 1 + }, + "results": [ + { + "project_name": "testproject", + "description": "Demo results", + "stop_date": "2017-12-28 16:08:43", + "case_name": "testcase", + "build_tag": null, + "user": null, + "installer": "fuel", + "scenario": "test-scenario", + "trust_indicator": null, + "public": "true", + "version": "euphrates", + "details": "", + "criteria": "PASS", + "_id": "5a45170bbb2092000e2643f4", + "start_date": "2017-12-28 14:44:27", + "pod_name": "testPod" + } + ] + } + } + }, + { + request: { + path: '/api/v1/results', + method: 'GET', + queryString: { + page: '1', + project: 'testproject' + } + }, + response: { + data: { + "pagination": { + "current_page": 1, + "total_pages": 1 + }, + "results": [ + { + "project_name": "testproject", + "description": "Demo results", + "stop_date": "2017-12-28 16:08:43", + "case_name": "testcase", + "build_tag": null, + "user": null, + "installer": "fuel", + "scenario": "test-scenario", + "trust_indicator": null, + "public": "true", + "version": "euphrates", + "details": "", + "criteria": "PASS", + "_id": "5a45170bbb2092000e2643f5", + "start_date": "2017-12-28 14:44:27", + "pod_name": "testPod" + } + ] + } + } + }, + { + request: { + path: '/api/v1/results', + method: 'GET', + queryString: { + page: '1', + project: 'testproject', + case: 'testcase' + } + }, + response: { + data: { + "pagination": { + "current_page": 1, + "total_pages": 1 + }, + "results": [ + { + "project_name": "testproject", + "description": "Demo results", + "stop_date": "2017-12-28 16:08:43", + "case_name": "testcase", + "build_tag": null, + "user": null, + "installer": "fuel", + "scenario": "test-scenario", + "trust_indicator": null, + "public": "true", + "version": "euphrates", + "details": "", + "criteria": "PASS", + "_id": "5a45170bbb2092000e2643f6", + "start_date": "2017-12-28 14:44:27", + "pod_name": "testPod" + } + ] + } + } + } + ]); + }); + + afterEach(function(){ + mock.teardown(); + }); + + it( 'should show the results page for anonymous user', function() { + browser.get(baseURL+"#/results"); + expect(element(by.cssContainingText(".ng-binding.ng-scope","Test Results")).isDisplayed()).toBe(true); + }); + + it( 'navigate anonymous user to results page', function() { + browser.get(baseURL); + var resultLink = element(by.linkText('Results')).click(); + var EC = browser.ExpectedConditions; + browser.wait(EC.urlContains(baseURL+ '#/results'), 10000); + }); + + it('Should show the results in results page for anonymous user ', function () { + browser.get(baseURL+"#/results"); + var row = element.all(by.repeater('(index, result) in ctrl.data.results')).first(); + var cells = row.all(by.tagName('td')); + expect(cells.get(0).getText()).toContain("5a45170bbb2092000e2643f4"); + }); + + it('Should show the results in results page related to the filters for anonymous user ', function () { + browser.get(baseURL+"#/results"); + var filter = element(by.model('ctrl.filter')); + var filterText = element(by.model('ctrl.filterText')); + filter.sendKeys('project'); + filterText.sendKeys('testproject'); + var buttonFilter = element(by.buttonText('Filter')); + buttonFilter.click(); + var row = element.all(by.repeater('(index, result) in ctrl.data.results')).first(); + var cells = row.all(by.tagName('td')); + expect(cells.get(0).getText()).toContain("5a45170bbb2092000e2643f5"); + filter.sendKeys('case'); + filterText.sendKeys('testcase') + buttonFilter.click(); + expect(cells.get(0).getText()).toContain("5a45170bbb2092000e2643f6"); + }); + it('Should not show the results in results page related to the filters for anonymous user ', function () { + browser.get(baseURL+"#/results"); + var filter = element(by.model('ctrl.filter')); + var filterText = element(by.model('ctrl.filterText')); + filter.sendKeys('project'); + filterText.sendKeys('testproject1'); + var buttonFilter = element(by.buttonText('Filter')); + buttonFilter.click(); + expect(element(by.css('.alert.alert-danger.ng-binding.ng-scope')) + .isDisplayed()).toBe(true); + }); + +}); + +describe('testing the result page for user', function () { + beforeEach(function(){ + mock([ + { + request: { + path: '/api/v1/profile', + method: 'GET' + }, + response: { + data: { + "fullname": "Test User", "_id": "79f82eey9a00c84bfhc7aed", + "user": "testUser", "groups": ["opnfv-testapi-users"], + "email": "testuser@test.com" + } + } + }, + { + request: { + path: '/api/v1/results', + method: 'GET', + queryString: { + page: '1' + } + }, + response: { + data: { + "pagination": { + "current_page": 1, + "total_pages": 1 + }, + "results": [ + { + "project_name": "testproject", + "description": "Demo results", + "stop_date": "2017-12-28 16:08:43", + "case_name": "testcase", + "build_tag": null, + "user": null, + "installer": "fuel", + "scenario": "test-scenario", + "trust_indicator": null, + "public": "true", + "version": "euphrates", + "details": "", + "criteria": "PASS", + "_id": "5a45170bbb2092000e2643f4", + "start_date": "2017-12-28 14:44:27", + "pod_name": "testPod" + } + ] + } + } + }, + { + request: { + path: '/api/v1/results', + method: 'GET', + queryString: { + page: '1', + project: 'testproject' + } + }, + response: { + data: { + "pagination": { + "current_page": 1, + "total_pages": 1 + }, + "results": [ + { + "project_name": "testproject", + "description": "Demo results", + "stop_date": "2017-12-28 16:08:43", + "case_name": "testcase", + "build_tag": null, + "user": null, + "installer": "fuel", + "scenario": "test-scenario", + "trust_indicator": null, + "public": "true", + "version": "euphrates", + "details": "", + "criteria": "PASS", + "_id": "5a45170bbb2092000e2643f5", + "start_date": "2017-12-28 14:44:27", + "pod_name": "testPod" + } + ] + } + } + }, + { + request: { + path: '/api/v1/results', + method: 'GET', + queryString: { + page: '1', + project: 'testproject', + case: 'testcase' + } + }, + response: { + data: { + "pagination": { + "current_page": 1, + "total_pages": 1 + }, + "results": [ + { + "project_name": "testproject", + "description": "Demo results", + "stop_date": "2017-12-28 16:08:43", + "case_name": "testcase", + "build_tag": null, + "user": null, + "installer": "fuel", + "scenario": "test-scenario", + "trust_indicator": null, + "public": "true", + "version": "euphrates", + "details": "", + "criteria": "PASS", + "_id": "5a45170bbb2092000e2643f6", + "start_date": "2017-12-28 14:44:27", + "pod_name": "testPod" + } + ] + } + } + } + ]); + }); + + afterEach(function(){ + mock.teardown(); + }); + + it( 'should show the results page for user', function() { + browser.get(baseURL+"#/results"); + expect(element(by.cssContainingText(".ng-binding.ng-scope","Test Results")).isDisplayed()).toBe(true); + }); + + it( 'navigate user to testCase page', function() { + browser.get(baseURL); + var resultLink = element(by.linkText('Results')).click(); + var EC = browser.ExpectedConditions; + browser.wait(EC.urlContains(baseURL+ '#/results'), 10000); + }); + + it('Should show the results in results page for user ', function () { + browser.get(baseURL+"#/results"); + var row = element.all(by.repeater('(index, result) in ctrl.data.results')).first(); + var cells = row.all(by.tagName('td')); + expect(cells.get(0).getText()).toContain("5a45170bbb2092000e2643f4"); + }); + + it('Should show the results in results page related to the filters for user ', function () { + browser.get(baseURL+"#/results"); + var filter = element(by.model('ctrl.filter')); + var filterText = element(by.model('ctrl.filterText')); + filter.sendKeys('project'); + filterText.sendKeys('testproject'); + var buttonFilter = element(by.buttonText('Filter')); + buttonFilter.click(); + var row = element.all(by.repeater('(index, result) in ctrl.data.results')).first(); + var cells = row.all(by.tagName('td')); + expect(cells.get(0).getText()).toContain("5a45170bbb2092000e2643f5"); + filter.sendKeys('case'); + filterText.sendKeys('testcase') + buttonFilter.click(); + expect(cells.get(0).getText()).toContain("5a45170bbb2092000e2643f6"); + }); + + it('Clear the filter', function () { + browser.get(baseURL+"#/results"); + var filter = element(by.model('ctrl.filter')); + var filterText = element(by.model('ctrl.filterText')); + filter.sendKeys('project'); + filterText.sendKeys('testproject'); + var buttonFilter = element(by.buttonText('Filter')); + buttonFilter.click(); + var row = element.all(by.repeater('(index, result) in ctrl.data.results')).first(); + var cells = row.all(by.tagName('td')); + expect(cells.get(0).getText()).toContain("5a45170bbb2092000e2643f5"); + var buttonClear = element(by.buttonText('Clear')); + buttonClear.click(); + var row = element.all(by.repeater('(index, result) in ctrl.data.results')).first(); + var cells = row.all(by.tagName('td')); + expect(cells.get(0).getText()).toContain("5a45170bbb2092000e2643f4"); + }); + it('Should not show the results in results page related to the filters for user ', function () { + browser.get(baseURL+"#/results"); + var filter = element(by.model('ctrl.filter')); + var filterText = element(by.model('ctrl.filterText')); + filter.sendKeys('project'); + filterText.sendKeys('testproject1'); + var buttonFilter = element(by.buttonText('Filter')); + buttonFilter.click(); + expect(element(by.css('.alert.alert-danger.ng-binding.ng-scope')) + .isDisplayed()).toBe(true); + }); + +});
\ No newline at end of file diff --git a/testapi/opnfv_testapi/tests/UI/e2e/scenarioControllerSpec.js b/testapi/opnfv_testapi/tests/UI/e2e/scenarioControllerSpec.js new file mode 100644 index 0000000..f97a621 --- /dev/null +++ b/testapi/opnfv_testapi/tests/UI/e2e/scenarioControllerSpec.js @@ -0,0 +1,1041 @@ +'use strict'; + +var mock = require('protractor-http-mock'); +var baseURL = "http://localhost:8000/" + +describe('testing the scenarios page for anonymous user', function () { + beforeEach(function(){ + mock([ + { + request: { + path: '/api/v1/scenarios', + method: 'GET' + }, + response: { + data: { + "scenarios": [ + { + "installers": [ + { + "installer": "fuel", + "versions": [ + { + "owner": "testUser", + "version": "colorado", + "projects": [ + { + "project": "yardstick", + "customs": [ + "dvs" + ], + "scores": [ + { + "date": "2016-12-11 01:45", + "score": "14/24" + }, + { + "date": "2016-12-15 05:28", + "score": "17/24" + }, + { + "date": "2016-12-17 03:41", + "score": "16/24" + }, + { + "date": "2018-01-22T18:30:00.000Z", + "score": "10/13" + } + ], + "trust_indicators": [ + { + "date": "2016-12-09 11:38", + "status": "silver" + }, + { + "date": "2016-12-25 08:22", + "status": "gold" + }, + { + "date": "2018-01-22T18:30:00.000Z", + "status": "sf" + }, + { + "date": "2018-01-17T18:30:00.000Z", + "status": "df" + } + ] + }, + { + "project": "functest", + "customs": [ + "vping_ssh", + "vping_userdata", + ], + "scores": [ + { + "date": "2016-12-09 11:28", + "score": "6/8" + }, + { + "date": "2016-12-14 15:34", + "score": "8/8" + }, + { + "date": "2016-12-19 13:22", + "score": "8/8" + }, + { + "date": "2016-12-22 18:17", + "score": "8/8" + }, + { + "date": "2016-12-25 08:22", + "score": "8/8" + } + ], + "trust_indicators": [ + { + "date": "2016-12-09 11:38", + "status": "silver" + } + ] + }, + { + "project": "sla", + "customs": [], + "scores": [ + { + "date": "2018-01-16T18:30:00.000Z", + "score": "sdS" + } + ], + "trust_indicators": [] + }, + { + "project": "dvsd", + "customs": [], + "scores": [], + "trust_indicators": [] + } + ] + }, + { + "owner": "dfgvds", + "version": "df", + "projects": [] + } + ] + }, + { + "installer": "fuel2", + "versions": [ + { + "owner": "testUser", + "version": "colorado", + "projects": [ + { + "project": "yardstick", + "customs": [ + "tc002", + "tc005", + "tc010", + "tc011" + ], + "scores": [ + { + "date": "2016-12-11 01:45", + "score": "14/24" + }, + { + "date": "2016-12-15 05:28", + "score": "17/24" + }, + { + "date": "2016-12-17 03:41", + "score": "16/24" + } + ], + "trust_indicators": [ + { + "date": "2016-12-09 11:38", + "status": "silver" + }, + { + "date": "2016-12-25 08:22", + "status": "gold" + } + ] + }, + { + "project": "functest", + "customs": [ + "vping_ssh", + "vping_userdata" + ], + "scores": [ + { + "date": "2016-12-09 11:28", + "score": "6/8" + }, + { + "date": "2016-12-14 15:34", + "score": "8/8" + } + ], + "trust_indicators": [ + { + "date": "2016-12-09 11:38", + "status": "silver" + } + ] + } + ] + } + ] + } + ], + "_id": "5a50fcacsdgdsgdasgfvb861c", + "name": "test-scenario", + "creation_date": "2018-01-06 22:13:24.160407" + } + ] + } + } + } + ]); + }); + + afterEach(function(){ + mock.teardown(); + }); + + it( 'should show the scenarios page for anonymous user', function() { + browser.get(baseURL+"#/scenarios"); + var EC = browser.ExpectedConditions; + browser.wait(EC.urlContains(baseURL+ '#/scenarios'), 10000); + var row = element.all(by.repeater('(index, scenario) in ctrl.data.scenarios')).first(); + var cells = row.all(by.tagName('td')); + expect(cells.get(1).getText()).toContain("test-scenario"); + var scenarioLink = element(by.linkText('test-scenario')).click(); + browser.wait(EC.urlContains(baseURL+ '#/scenarios/test-scenario'), 10000); + }); + + it( 'should not show the add installer option for anonymous user', function() { + browser.get(baseURL+"#/scenarios/test-scenario"); + var EC = browser.ExpectedConditions; + browser.wait(EC.urlContains(baseURL+ '#/scenarios/test-scenario'), 10000); + var buttonAdd = element(by.xpath('//*[@id="ng-app"]/body/div/div[1]/div/table/tbody/tr[4]/td[2]/div[2]/button')) + expect(buttonAdd.isDisplayed()).toBe(false); + }); + + it( 'Expand installers by anonymous user', function() { + browser.get(baseURL+"#/scenarios/test-scenario"); + var EC = browser.ExpectedConditions; + browser.wait(EC.urlContains(baseURL+ '#/scenarios/test-scenario'), 10000); + var installerShow = element(by.xpath('//*[@id="ng-app"]/body/div/div[1]/div/table/tbody/tr[4]/td[2]/div[1]/a/p')) + installerShow.click(); + var row = element.all(by.repeater('(indexI, installer) in ctrl.data.scenarios[0].installers')).first(); + var cells = row.all(by.tagName('td')); + expect(cells.get(1).getText()).toContain("fuel"); + }); + + it( 'should not show the delete installer option for anonymous user', function() { + browser.get(baseURL+"#/scenarios/test-scenario"); + var EC = browser.ExpectedConditions; + browser.wait(EC.urlContains(baseURL+ '#/scenarios/test-scenario'), 10000); + var installersShow = element(by.xpath('//*[@id="ng-app"]/body/div/div[1]/div/table/tbody/tr[4]/td[2]/div[1]/a/p')) + installersShow.click(); + var installerDelete = element(by.xpath('//*[@id="ng-app"]/body/div/div[1]/div/table/tbody/tr[4]/td[2]/div[3]/div/table/tbody/tr[1]/td[3]/button')) + expect(installerDelete.isDisplayed()).toBe(false); + }); + + it( 'Expand installer by anonymous user', function() { + browser.get(baseURL+"#/scenarios/test-scenario"); + var EC = browser.ExpectedConditions; + browser.wait(EC.urlContains(baseURL+ '#/scenarios/test-scenario'), 10000); + var installersShow = element(by.xpath('//*[@id="ng-app"]/body/div/div[1]/div/table/tbody/tr[4]/td[2]/div[1]/a/p')) + installersShow.click(); + var installerShow = element(by.xpath('//*[@id="ng-app"]/body/div/div[1]/div/table/tbody/tr[4]/td[2]/div[3]/div/table/tbody/tr[1]/td[2]/a')) + installerShow.click(); + var versionsShow = element(by.xpath('//*[@id="ng-app"]/body/div/div[1]/div/table/tbody/tr[4]/td[2]/div[3]/div/table/tbody/tr[2]/td[2]/div[1]/a/p')) + expect(versionsShow.isDisplayed()).toBe(true) + }); + + it( 'Expand versions by anonymous user', function() { + browser.get(baseURL+"#/scenarios/test-scenario"); + var EC = browser.ExpectedConditions; + browser.wait(EC.urlContains(baseURL+ '#/scenarios/test-scenario'), 10000); + var installersShow = element(by.xpath('//*[@id="ng-app"]/body/div/div[1]/div/table/tbody/tr[4]/td[2]/div[1]/a/p')) + installersShow.click(); + var installerShow = element(by.xpath('//*[@id="ng-app"]/body/div/div[1]/div/table/tbody/tr[4]/td[2]/div[3]/div/table/tbody/tr[1]/td[2]/a')) + installerShow.click(); + var versionsShow = element(by.xpath('//*[@id="ng-app"]/body/div/div[1]/div/table/tbody/tr[4]/td[2]/div[3]/div/table/tbody/tr[2]/td[2]/div[1]/a/p')) + versionsShow.click(); + var versionShow = element(by.xpath('//*[@id="ng-app"]/body/div/div[1]/div/table/tbody/tr[4]/td[2]/div[3]/div/table/tbody/tr[2]/td[2]/div[3]/div/table/tbody/tr[1]/td[2]/a')) + expect(versionShow.isDisplayed()).toBe(true); + }); + + it( 'Expand version by anonymous user', function() { + browser.get(baseURL+"#/scenarios/test-scenario"); + var EC = browser.ExpectedConditions; + browser.wait(EC.urlContains(baseURL+ '#/scenarios/test-scenario'), 10000); + var installersShow = element(by.xpath('//*[@id="ng-app"]/body/div/div[1]/div/table/tbody/tr[4]/td[2]/div[1]/a/p')) + installersShow.click(); + var installerShow = element(by.xpath('//*[@id="ng-app"]/body/div/div[1]/div/table/tbody/tr[4]/td[2]/div[3]/div/table/tbody/tr[1]/td[2]/a')) + installerShow.click(); + var versionsShow = element(by.xpath('//*[@id="ng-app"]/body/div/div[1]/div/table/tbody/tr[4]/td[2]/div[3]/div/table/tbody/tr[2]/td[2]/div[1]/a/p')) + versionsShow.click(); + var versionShow = element(by.xpath('//*[@id="ng-app"]/body/div/div[1]/div/table/tbody/tr[4]/td[2]/div[3]/div/table/tbody/tr[2]/td[2]/div[3]/div/table/tbody/tr[1]/td[2]/a')) + versionShow.click() + var projectsShow = element(by.xpath('//*[@id="ng-app"]/body/div/div[1]/div/table/tbody/tr[4]/td[2]/div[3]/div/table/tbody/tr[2]/td[2]/div[3]/div/table/tbody/tr[3]/td[2]/div[1]/a')) + expect(projectsShow.isDisplayed()).toBe(true); + }); + + it( 'Expand projects by anonymous user', function() { + browser.get(baseURL+"#/scenarios/test-scenario"); + var EC = browser.ExpectedConditions; + browser.wait(EC.urlContains(baseURL+ '#/scenarios/test-scenario'), 10000); + var installersShow = element(by.xpath('//*[@id="ng-app"]/body/div/div[1]/div/table/tbody/tr[4]/td[2]/div[1]/a/p')) + installersShow.click(); + var installerShow = element(by.xpath('//*[@id="ng-app"]/body/div/div[1]/div/table/tbody/tr[4]/td[2]/div[3]/div/table/tbody/tr[1]/td[2]/a')) + installerShow.click(); + var versionsShow = element(by.xpath('//*[@id="ng-app"]/body/div/div[1]/div/table/tbody/tr[4]/td[2]/div[3]/div/table/tbody/tr[2]/td[2]/div[1]/a/p')) + versionsShow.click(); + var versionShow = element(by.xpath('//*[@id="ng-app"]/body/div/div[1]/div/table/tbody/tr[4]/td[2]/div[3]/div/table/tbody/tr[2]/td[2]/div[3]/div/table/tbody/tr[1]/td[2]/a')) + versionShow.click() + var projectsShow = element(by.xpath('//*[@id="ng-app"]/body/div/div[1]/div/table/tbody/tr[4]/td[2]/div[3]/div/table/tbody/tr[2]/td[2]/div[3]/div/table/tbody/tr[3]/td[2]/div[1]/a')) + projectsShow.click(); + var projectShow = element(by.xpath('//*[@id="ng-app"]/body/div/div[1]/div/table/tbody/tr[4]/td[2]/div[3]/div/table/tbody/tr[2]/td[2]/div[3]/div/table/tbody/tr[3]/td[2]/div[3]/div/table/tbody/tr[1]/td[2]/a')) + expect(projectShow.isDisplayed()).toBe(true) + }); + + it( 'Expand project by anonymous user', function() { + browser.get(baseURL+"#/scenarios/test-scenario"); + var EC = browser.ExpectedConditions; + browser.wait(EC.urlContains(baseURL+ '#/scenarios/test-scenario'), 10000); + var installersShow = element(by.xpath('//*[@id="ng-app"]/body/div/div[1]/div/table/tbody/tr[4]/td[2]/div[1]/a/p')) + installersShow.click(); + var installerShow = element(by.xpath('//*[@id="ng-app"]/body/div/div[1]/div/table/tbody/tr[4]/td[2]/div[3]/div/table/tbody/tr[1]/td[2]/a')) + installerShow.click(); + var versionsShow = element(by.xpath('//*[@id="ng-app"]/body/div/div[1]/div/table/tbody/tr[4]/td[2]/div[3]/div/table/tbody/tr[2]/td[2]/div[1]/a/p')) + versionsShow.click(); + var versionShow = element(by.xpath('//*[@id="ng-app"]/body/div/div[1]/div/table/tbody/tr[4]/td[2]/div[3]/div/table/tbody/tr[2]/td[2]/div[3]/div/table/tbody/tr[1]/td[2]/a')) + versionShow.click() + var projectsShow = element(by.xpath('//*[@id="ng-app"]/body/div/div[1]/div/table/tbody/tr[4]/td[2]/div[3]/div/table/tbody/tr[2]/td[2]/div[3]/div/table/tbody/tr[3]/td[2]/div[1]/a')) + projectsShow.click(); + var projectShow = element(by.xpath('//*[@id="ng-app"]/body/div/div[1]/div/table/tbody/tr[4]/td[2]/div[3]/div/table/tbody/tr[2]/td[2]/div[3]/div/table/tbody/tr[3]/td[2]/div[3]/div/table/tbody/tr[1]/td[2]/a')) + projectShow.click(); + var customsShow = element(by.xpath('//*[@id="ng-app"]/body/div/div[1]/div/table/tbody/tr[4]/td[2]/div[3]/div/table/tbody/tr[2]/td[2]/div[3]/div/table/tbody/tr[3]/td[2]/div[3]/div/table/tbody/tr[4]/td[2]/a/p')) + expect(customsShow.isDisplayed()).toBe(true) + var trustIndicatorsShow = element(by.xpath('//*[@id="ng-app"]/body/div/div[1]/div/table/tbody/tr[4]/td[2]/div[3]/div/table/tbody/tr[2]/td[2]/div[3]/div/table/tbody/tr[3]/td[2]/div[3]/div/table/tbody/tr[2]/td[2]/a/p')) + expect(trustIndicatorsShow.isDisplayed()).toBe(true) + var scoresShow = element(by.xpath('//*[@id="ng-app"]/body/div/div[1]/div/table/tbody/tr[4]/td[2]/div[3]/div/table/tbody/tr[2]/td[2]/div[3]/div/table/tbody/tr[3]/td[2]/div[3]/div/table/tbody/tr[3]/td[2]/a/p')) + expect(scoresShow.isDisplayed()).toBe(true) + }); + +}); + + +describe('testing the scenarios page for anonymous user', function () { + beforeEach(function(){ + mock([ + { + request: { + path: '/api/v1/scenarios', + method: 'GET' + }, + response: { + data: { + "scenarios": [ + { + "installers": [ + { + "installer": "fuel", + "versions": [ + { + "owner": "testUser", + "version": "colorado", + "projects": [ + { + "project": "yardstick", + "customs": [ + "dvs" + ], + "scores": [ + { + "date": "2016-12-11 01:45", + "score": "14/24" + }, + { + "date": "2016-12-15 05:28", + "score": "17/24" + }, + { + "date": "2016-12-17 03:41", + "score": "16/24" + }, + { + "date": "2018-01-22T18:30:00.000Z", + "score": "10/13" + } + ], + "trust_indicators": [ + { + "date": "2016-12-09 11:38", + "status": "silver" + }, + { + "date": "2016-12-25 08:22", + "status": "gold" + }, + { + "date": "2018-01-22T18:30:00.000Z", + "status": "sf" + }, + { + "date": "2018-01-17T18:30:00.000Z", + "status": "df" + } + ] + }, + { + "project": "functest", + "customs": [ + "vping_ssh", + "vping_userdata", + ], + "scores": [ + { + "date": "2016-12-09 11:28", + "score": "6/8" + }, + { + "date": "2016-12-14 15:34", + "score": "8/8" + }, + { + "date": "2016-12-19 13:22", + "score": "8/8" + }, + { + "date": "2016-12-22 18:17", + "score": "8/8" + }, + { + "date": "2016-12-25 08:22", + "score": "8/8" + } + ], + "trust_indicators": [ + { + "date": "2016-12-09 11:38", + "status": "silver" + } + ] + }, + { + "project": "sla", + "customs": [], + "scores": [ + { + "date": "2018-01-16T18:30:00.000Z", + "score": "sdS" + } + ], + "trust_indicators": [] + }, + { + "project": "dvsd", + "customs": [], + "scores": [], + "trust_indicators": [] + } + ] + }, + { + "owner": "dfgvds", + "version": "df", + "projects": [] + } + ] + }, + { + "installer": "fuel2", + "versions": [ + { + "owner": "testUser", + "version": "colorado", + "projects": [ + { + "project": "yardstick", + "customs": [ + "tc002", + "tc005", + "tc010", + "tc011" + ], + "scores": [ + { + "date": "2016-12-11 01:45", + "score": "14/24" + }, + { + "date": "2016-12-15 05:28", + "score": "17/24" + }, + { + "date": "2016-12-17 03:41", + "score": "16/24" + } + ], + "trust_indicators": [ + { + "date": "2016-12-09 11:38", + "status": "silver" + }, + { + "date": "2016-12-25 08:22", + "status": "gold" + } + ] + }, + { + "project": "functest", + "customs": [ + "vping_ssh", + "vping_userdata" + ], + "scores": [ + { + "date": "2016-12-09 11:28", + "score": "6/8" + }, + { + "date": "2016-12-14 15:34", + "score": "8/8" + } + ], + "trust_indicators": [ + { + "date": "2016-12-09 11:38", + "status": "silver" + } + ] + } + ] + } + ] + } + ], + "_id": "5a50fcacsdgdsgdasgfvb861c", + "name": "test-scenario", + "creation_date": "2018-01-06 22:13:24.160407" + } + ] + } + } + }, + { + request: { + path: '/api/v1/profile', + method: 'GET' + }, + response: { + data: { + "fullname": "Test User", "_id": "79f82eey9a00c84bfhc7aed", + "user": "testUser", "groups": ["opnfv-testapi-users"], + "email": "testuser@test.com" + } + } + }, + { + request: { + path: '/api/v1/scenarios/test-scenario/installers', + method: 'POST' + }, + response: { + status : 200 + } + }, + { + request: { + path: '/api/v1/scenarios/test-scenario/installers', + method: 'DELETE' + }, + response: { + status : 200 + } + }, + { + request: { + path: '/api/v1/scenarios/test-scenario/versions', + method: 'POST', + queryString: { + installer: 'fuel' + } + }, + response: { + status : 200 + } + }, + { + request: { + path: '/api/v1/scenarios/test-scenario/versions', + method: 'DELETE', + queryString: { + installer: 'fuel' + } + }, + response: { + status : 200 + } + }, + { + request: { + path: '/api/v1/scenarios/test-scenario/projects', + method: 'POST', + queryString: { + installer: 'fuel', + version: 'colorado' + } + }, + response: { + status : 200 + } + }, + { + request: { + path: '/api/v1/scenarios/test-scenario/projects', + method: 'DELETE', + queryString: { + installer: 'fuel', + version: 'colorado' + } + }, + response: { + status : 200 + } + }, + { + request: { + path: '/api/v1/scenarios/test-scenario/customs', + method: 'POST', + queryString: { + installer: 'fuel', + version: 'colorado', + project: 'yardstick' + } + }, + response: { + status : 200 + } + }, + { + request: { + path: '/api/v1/scenarios/test-scenario/customs', + method: 'DELETE', + queryString: { + installer: 'fuel', + version: 'colorado', + project: 'yardstick' + } + }, + response: { + status : 200 + } + } + ]); + }); + + afterEach(function(){ + mock.teardown(); + }); + + it( 'should show the scenarios page for user', function() { + browser.get(baseURL+"#/scenarios"); + var EC = browser.ExpectedConditions; + browser.wait(EC.urlContains(baseURL+ '#/scenarios'), 10000); + var row = element.all(by.repeater('(index, scenario) in ctrl.data.scenarios')).first(); + var cells = row.all(by.tagName('td')); + expect(cells.get(1).getText()).toContain("test-scenario"); + var scenarioLink = element(by.linkText('test-scenario')).click(); + browser.wait(EC.urlContains(baseURL+ '#/scenarios/test-scenario'), 10000); + }); + + it( 'should not show the add installer option for user', function() { + browser.get(baseURL+"#/scenarios/test-scenario"); + var EC = browser.ExpectedConditions; + browser.wait(EC.urlContains(baseURL+ '#/scenarios/test-scenario'), 10000); + var buttonAdd = element(by.xpath('//*[@id="ng-app"]/body/div/div[1]/div/table/tbody/tr[4]/td[2]/div[2]/button')) + expect(buttonAdd.isDisplayed()).toBe(true); + }); + + it('add installer', function(){ + browser.get(baseURL+"#/scenarios/test-scenario"); + var EC = browser.ExpectedConditions; + browser.wait(EC.urlContains(baseURL+ '#/scenarios/test-scenario'), 10000); + var buttonAdd = element(by.xpath('//*[@id="ng-app"]/body/div/div[1]/div/table/tbody/tr[4]/td[2]/div[2]/button')) + buttonAdd.click(); + var name = element(by.model('installerModalCtrl.installer.installer')); + var EC = browser.ExpectedConditions; + browser.wait(EC.visibilityOf(name), 5000); + name.sendKeys('test'); + var buttonOk = element(by.xpath('//*[@id="ng-app"]/body/div[3]/div/div/div/div[2]/button[1]')) + buttonOk.click() + expect(element(by.cssContainingText(".alert","Installers are successfully updated.")) + .isDisplayed()).toBe(true); + + }); + + it( 'Expand installers by user', function() { + browser.get(baseURL+"#/scenarios/test-scenario"); + var EC = browser.ExpectedConditions; + browser.wait(EC.urlContains(baseURL+ '#/scenarios/test-scenario'), 10000); + var installerShow = element(by.xpath('//*[@id="ng-app"]/body/div/div[1]/div/table/tbody/tr[4]/td[2]/div[1]/a/p')) + installerShow.click(); + var row = element.all(by.repeater('(indexI, installer) in ctrl.data.scenarios[0].installers')).first(); + var cells = row.all(by.tagName('td')); + expect(cells.get(1).getText()).toContain("fuel"); + }); + + it( 'should show the delete installer option for user', function() { + browser.get(baseURL+"#/scenarios/test-scenario"); + var EC = browser.ExpectedConditions; + browser.wait(EC.urlContains(baseURL+ '#/scenarios/test-scenario'), 10000); + var installersShow = element(by.xpath('//*[@id="ng-app"]/body/div/div[1]/div/table/tbody/tr[4]/td[2]/div[1]/a/p')) + installersShow.click(); + var installerDelete = element(by.xpath('//*[@id="ng-app"]/body/div/div[1]/div/table/tbody/tr[4]/td[2]/div[3]/div/table/tbody/tr[1]/td[3]/button')) + expect(installerDelete.isDisplayed()).toBe(true); + }); + + it( 'delete installer', function() { + browser.get(baseURL+"#/scenarios/test-scenario"); + var EC = browser.ExpectedConditions; + browser.wait(EC.urlContains(baseURL+ '#/scenarios/test-scenario'), 10000); + var installersShow = element(by.xpath('//*[@id="ng-app"]/body/div/div[1]/div/table/tbody/tr[4]/td[2]/div[1]/a/p')) + installersShow.click(); + var installerDelete = element(by.xpath('//*[@id="ng-app"]/body/div/div[1]/div/table/tbody/tr[4]/td[2]/div[3]/div/table/tbody/tr[1]/td[3]/button')) + installerDelete.click() + var buttonOK = element(by.buttonText('Ok')); + buttonOK.click(); + expect(element(by.cssContainingText(".alert","Installer is successfully deleted.")) + .isDisplayed()).toBe(true); + }); + + it( 'Expand installer by user', function() { + browser.get(baseURL+"#/scenarios/test-scenario"); + var EC = browser.ExpectedConditions; + browser.wait(EC.urlContains(baseURL+ '#/scenarios/test-scenario'), 10000); + var installersShow = element(by.xpath('//*[@id="ng-app"]/body/div/div[1]/div/table/tbody/tr[4]/td[2]/div[1]/a/p')) + installersShow.click(); + var installerShow = element(by.xpath('//*[@id="ng-app"]/body/div/div[1]/div/table/tbody/tr[4]/td[2]/div[3]/div/table/tbody/tr[1]/td[2]/a')) + installerShow.click(); + var versionsShow = element(by.xpath('//*[@id="ng-app"]/body/div/div[1]/div/table/tbody/tr[4]/td[2]/div[3]/div/table/tbody/tr[2]/td[2]/div[1]/a/p')) + expect(versionsShow.isDisplayed()).toBe(true) + }); + + it( 'add version for an installer', function() { + browser.get(baseURL+"#/scenarios/test-scenario"); + var EC = browser.ExpectedConditions; + browser.wait(EC.urlContains(baseURL+ '#/scenarios/test-scenario'), 10000); + var installersShow = element(by.xpath('//*[@id="ng-app"]/body/div/div[1]/div/table/tbody/tr[4]/td[2]/div[1]/a/p')) + installersShow.click(); + var installerShow = element(by.xpath('//*[@id="ng-app"]/body/div/div[1]/div/table/tbody/tr[4]/td[2]/div[3]/div/table/tbody/tr[1]/td[2]/a')) + installerShow.click(); + var versionAdd = element(by.xpath('//*[@id="ng-app"]/body/div/div[1]/div/table/tbody/tr[4]/td[2]/div[3]/div/table/tbody/tr[2]/td[2]/div[2]/button')) + versionAdd.click() + var version = element(by.model('versionModalCtrl.version.version')); + browser.wait(EC.visibilityOf(version), 5000); + version.sendKeys('testV'); + var owner = element(by.model('versionModalCtrl.version.owner')); + owner.sendKeys('testOwner'); + var buttonOk = element(by.xpath('//*[@id="ng-app"]/body/div[3]/div/div/div/div[2]/button[1]')) + buttonOk.click() + expect(element(by.cssContainingText(".alert","Versions are successfully updated.")) + .isDisplayed()).toBe(true); + }); + + it( 'Expand versions by user', function() { + browser.get(baseURL+"#/scenarios/test-scenario"); + var EC = browser.ExpectedConditions; + browser.wait(EC.urlContains(baseURL+ '#/scenarios/test-scenario'), 10000); + var installersShow = element(by.xpath('//*[@id="ng-app"]/body/div/div[1]/div/table/tbody/tr[4]/td[2]/div[1]/a/p')) + installersShow.click(); + var installerShow = element(by.xpath('//*[@id="ng-app"]/body/div/div[1]/div/table/tbody/tr[4]/td[2]/div[3]/div/table/tbody/tr[1]/td[2]/a')) + installerShow.click(); + var versionsShow = element(by.xpath('//*[@id="ng-app"]/body/div/div[1]/div/table/tbody/tr[4]/td[2]/div[3]/div/table/tbody/tr[2]/td[2]/div[1]/a/p')) + versionsShow.click(); + var versionShow = element(by.xpath('//*[@id="ng-app"]/body/div/div[1]/div/table/tbody/tr[4]/td[2]/div[3]/div/table/tbody/tr[2]/td[2]/div[3]/div/table/tbody/tr[1]/td[2]/a')) + expect(versionShow.isDisplayed()).toBe(true); + var installerAdd = element(by.xpath('//*[@id="ng-app"]/body/div/div[1]/div/table/tbody/tr[4]/td[2]/div[2]/button')) + var installerDelete = element(by.xpath('//*[@id="ng-app"]/body/div/div[1]/div/table/tbody/tr[4]/td[2]/div[3]/div/table/tbody/tr[1]/td[3]/button')) + expect(installerAdd.isDisplayed()).toBe(false); + expect(installerDelete.isDisplayed()).toBe(false) + }); + + it( 'delete version', function() { + browser.get(baseURL+"#/scenarios/test-scenario"); + var EC = browser.ExpectedConditions; + browser.wait(EC.urlContains(baseURL+ '#/scenarios/test-scenario'), 10000); + var installersShow = element(by.xpath('//*[@id="ng-app"]/body/div/div[1]/div/table/tbody/tr[4]/td[2]/div[1]/a/p')) + installersShow.click(); + var installerShow = element(by.xpath('//*[@id="ng-app"]/body/div/div[1]/div/table/tbody/tr[4]/td[2]/div[3]/div/table/tbody/tr[1]/td[2]/a')) + installerShow.click(); + var versionsShow = element(by.xpath('//*[@id="ng-app"]/body/div/div[1]/div/table/tbody/tr[4]/td[2]/div[3]/div/table/tbody/tr[2]/td[2]/div[1]/a/p')) + versionsShow.click(); + var versionShow = element(by.xpath('//*[@id="ng-app"]/body/div/div[1]/div/table/tbody/tr[4]/td[2]/div[3]/div/table/tbody/tr[2]/td[2]/div[3]/div/table/tbody/tr[1]/td[2]/a')) + versionShow.click() + var versionDelete = element(by.xpath('//*[@id="ng-app"]/body/div/div[1]/div/table/tbody/tr[4]/td[2]/div[3]/div/table/tbody/tr[2]/td[2]/div[3]/div/table/tbody[1]/tr[1]/td[3]/button')) + versionDelete.click() + var buttonOK = element(by.buttonText('Ok')); + buttonOK.click(); + expect(element(by.cssContainingText(".alert","Versions are successfully deleted.")) + .isDisplayed()).toBe(true); + }); + + it( 'Expand version by user', function() { + browser.get(baseURL+"#/scenarios/test-scenario"); + var EC = browser.ExpectedConditions; + browser.wait(EC.urlContains(baseURL+ '#/scenarios/test-scenario'), 10000); + var installersShow = element(by.xpath('//*[@id="ng-app"]/body/div/div[1]/div/table/tbody/tr[4]/td[2]/div[1]/a/p')) + installersShow.click(); + var installerShow = element(by.xpath('//*[@id="ng-app"]/body/div/div[1]/div/table/tbody/tr[4]/td[2]/div[3]/div/table/tbody/tr[1]/td[2]/a')) + installerShow.click(); + var versionsShow = element(by.xpath('//*[@id="ng-app"]/body/div/div[1]/div/table/tbody/tr[4]/td[2]/div[3]/div/table/tbody/tr[2]/td[2]/div[1]/a/p')) + versionsShow.click(); + var versionShow = element(by.xpath('//*[@id="ng-app"]/body/div/div[1]/div/table/tbody/tr[4]/td[2]/div[3]/div/table/tbody/tr[2]/td[2]/div[3]/div/table/tbody/tr[1]/td[2]/a')) + versionShow.click() + var projectsShow = element(by.xpath('//*[@id="ng-app"]/body/div/div[1]/div/table/tbody/tr[4]/td[2]/div[3]/div/table/tbody/tr[2]/td[2]/div[3]/div/table/tbody/tr[3]/td[2]/div[1]/a')) + expect(projectsShow.isDisplayed()).toBe(true); + }); + + it( 'add project', function() { + browser.get(baseURL+"#/scenarios/test-scenario"); + var EC = browser.ExpectedConditions; + browser.wait(EC.urlContains(baseURL+ '#/scenarios/test-scenario'), 10000); + var installersShow = element(by.xpath('//*[@id="ng-app"]/body/div/div[1]/div/table/tbody/tr[4]/td[2]/div[1]/a/p')) + installersShow.click(); + var installerShow = element(by.xpath('//*[@id="ng-app"]/body/div/div[1]/div/table/tbody/tr[4]/td[2]/div[3]/div/table/tbody/tr[1]/td[2]/a')) + installerShow.click(); + var versionsShow = element(by.xpath('//*[@id="ng-app"]/body/div/div[1]/div/table/tbody/tr[4]/td[2]/div[3]/div/table/tbody/tr[2]/td[2]/div[1]/a/p')) + versionsShow.click(); + var versionShow = element(by.xpath('//*[@id="ng-app"]/body/div/div[1]/div/table/tbody/tr[4]/td[2]/div[3]/div/table/tbody/tr[2]/td[2]/div[3]/div/table/tbody/tr[1]/td[2]/a')) + versionShow.click() + var projectAdd = element(by.xpath('//*[@id="ng-app"]/body/div/div[1]/div/table/tbody/tr[4]/td[2]/div[3]/div/table/tbody/tr[2]/td[2]/div[3]/div/table/tbody/tr[3]/td[2]/div[2]/button')) + projectAdd.click() + var project = element(by.model('projectModalCtrl.project.project')); + browser.wait(EC.visibilityOf(project), 5000); + project.sendKeys('testP'); + var buttonOk = element(by.xpath('//*[@id="ng-app"]/body/div[3]/div/div/div/div[2]/button[1]')) + buttonOk.click() + expect(element(by.cssContainingText(".alert","Projects are successfully updated.")) + .isDisplayed()).toBe(true); + }); + + it( 'Expand projects by user', function() { + browser.get(baseURL+"#/scenarios/test-scenario"); + var EC = browser.ExpectedConditions; + browser.wait(EC.urlContains(baseURL+ '#/scenarios/test-scenario'), 10000); + var installersShow = element(by.xpath('//*[@id="ng-app"]/body/div/div[1]/div/table/tbody/tr[4]/td[2]/div[1]/a/p')) + installersShow.click(); + var installerShow = element(by.xpath('//*[@id="ng-app"]/body/div/div[1]/div/table/tbody/tr[4]/td[2]/div[3]/div/table/tbody/tr[1]/td[2]/a')) + installerShow.click(); + var versionsShow = element(by.xpath('//*[@id="ng-app"]/body/div/div[1]/div/table/tbody/tr[4]/td[2]/div[3]/div/table/tbody/tr[2]/td[2]/div[1]/a/p')) + versionsShow.click(); + var versionShow = element(by.xpath('//*[@id="ng-app"]/body/div/div[1]/div/table/tbody/tr[4]/td[2]/div[3]/div/table/tbody/tr[2]/td[2]/div[3]/div/table/tbody/tr[1]/td[2]/a')) + versionShow.click() + var projectsShow = element(by.xpath('//*[@id="ng-app"]/body/div/div[1]/div/table/tbody/tr[4]/td[2]/div[3]/div/table/tbody/tr[2]/td[2]/div[3]/div/table/tbody/tr[3]/td[2]/div[1]/a')) + projectsShow.click(); + var projectShow = element(by.xpath('//*[@id="ng-app"]/body/div/div[1]/div/table/tbody/tr[4]/td[2]/div[3]/div/table/tbody/tr[2]/td[2]/div[3]/div/table/tbody/tr[3]/td[2]/div[3]/div/table/tbody/tr[1]/td[2]/a')) + expect(projectShow.isDisplayed()).toBe(true) + var versionAdd = element(by.xpath('//*[@id="ng-app"]/body/div/div[1]/div/table/tbody/tr[4]/td[2]/div[3]/div/table/tbody/tr[2]/td[2]/div[2]/button')) + var versionDelete = element(by.xpath('//*[@id="ng-app"]/body/div/div[1]/div/table/tbody/tr[4]/td[2]/div[3]/div/table/tbody/tr[2]/td[2]/div[3]/div/table/tbody/tr[1]/td[3]/button')) + expect(versionAdd.isDisplayed()).toBe(false) + expect(versionDelete.isDisplayed()).toBe(false) + }); + + it( 'delete project', function() { + browser.get(baseURL+"#/scenarios/test-scenario"); + var EC = browser.ExpectedConditions; + browser.wait(EC.urlContains(baseURL+ '#/scenarios/test-scenario'), 10000); + var installersShow = element(by.xpath('//*[@id="ng-app"]/body/div/div[1]/div/table/tbody/tr[4]/td[2]/div[1]/a/p')) + installersShow.click(); + var installerShow = element(by.xpath('//*[@id="ng-app"]/body/div/div[1]/div/table/tbody/tr[4]/td[2]/div[3]/div/table/tbody/tr[1]/td[2]/a')) + installerShow.click(); + var versionsShow = element(by.xpath('//*[@id="ng-app"]/body/div/div[1]/div/table/tbody/tr[4]/td[2]/div[3]/div/table/tbody/tr[2]/td[2]/div[1]/a/p')) + versionsShow.click(); + var versionShow = element(by.xpath('//*[@id="ng-app"]/body/div/div[1]/div/table/tbody/tr[4]/td[2]/div[3]/div/table/tbody/tr[2]/td[2]/div[3]/div/table/tbody/tr[1]/td[2]/a')) + versionShow.click() + var projectsShow = element(by.xpath('//*[@id="ng-app"]/body/div/div[1]/div/table/tbody/tr[4]/td[2]/div[3]/div/table/tbody/tr[2]/td[2]/div[3]/div/table/tbody/tr[3]/td[2]/div[1]/a')) + projectsShow.click(); + var projectDelete = element(by.xpath('//*[@id="ng-app"]/body/div/div[1]/div/table/tbody/tr[4]/td[2]/div[3]/div/table/tbody/tr[2]/td[2]/div[3]/div/table/tbody/tr[3]/td[2]/div[3]/div/table/tbody[1]/tr[1]/td[3]/button')) + projectDelete.click() + var buttonOK = element(by.buttonText('Ok')); + buttonOK.click(); + expect(element(by.cssContainingText(".alert","Projects are successfully Deleted.")) + .isDisplayed()).toBe(true); + }); + + it( 'Expand project by user', function() { + browser.get(baseURL+"#/scenarios/test-scenario"); + var EC = browser.ExpectedConditions; + browser.wait(EC.urlContains(baseURL+ '#/scenarios/test-scenario'), 10000); + var installersShow = element(by.xpath('//*[@id="ng-app"]/body/div/div[1]/div/table/tbody/tr[4]/td[2]/div[1]/a/p')) + installersShow.click(); + var installerShow = element(by.xpath('//*[@id="ng-app"]/body/div/div[1]/div/table/tbody/tr[4]/td[2]/div[3]/div/table/tbody/tr[1]/td[2]/a')) + installerShow.click(); + var versionsShow = element(by.xpath('//*[@id="ng-app"]/body/div/div[1]/div/table/tbody/tr[4]/td[2]/div[3]/div/table/tbody/tr[2]/td[2]/div[1]/a/p')) + versionsShow.click(); + var versionShow = element(by.xpath('//*[@id="ng-app"]/body/div/div[1]/div/table/tbody/tr[4]/td[2]/div[3]/div/table/tbody/tr[2]/td[2]/div[3]/div/table/tbody/tr[1]/td[2]/a')) + versionShow.click() + var projectsShow = element(by.xpath('//*[@id="ng-app"]/body/div/div[1]/div/table/tbody/tr[4]/td[2]/div[3]/div/table/tbody/tr[2]/td[2]/div[3]/div/table/tbody/tr[3]/td[2]/div[1]/a')) + projectsShow.click(); + var projectShow = element(by.xpath('//*[@id="ng-app"]/body/div/div[1]/div/table/tbody/tr[4]/td[2]/div[3]/div/table/tbody/tr[2]/td[2]/div[3]/div/table/tbody/tr[3]/td[2]/div[3]/div/table/tbody/tr[1]/td[2]/a')) + projectShow.click(); + var customsShow = element(by.xpath('//*[@id="ng-app"]/body/div/div[1]/div/table/tbody/tr[4]/td[2]/div[3]/div/table/tbody/tr[2]/td[2]/div[3]/div/table/tbody/tr[3]/td[2]/div[3]/div/table/tbody/tr[4]/td[2]/a/p')) + expect(customsShow.isDisplayed()).toBe(true) + var trustIndicatorsShow = element(by.xpath('//*[@id="ng-app"]/body/div/div[1]/div/table/tbody/tr[4]/td[2]/div[3]/div/table/tbody/tr[2]/td[2]/div[3]/div/table/tbody/tr[3]/td[2]/div[3]/div/table/tbody/tr[2]/td[2]/a/p')) + expect(trustIndicatorsShow.isDisplayed()).toBe(true) + var scoresShow = element(by.xpath('//*[@id="ng-app"]/body/div/div[1]/div/table/tbody/tr[4]/td[2]/div[3]/div/table/tbody/tr[2]/td[2]/div[3]/div/table/tbody/tr[3]/td[2]/div[3]/div/table/tbody/tr[3]/td[2]/a/p')) + expect(scoresShow.isDisplayed()).toBe(true) + }); + + it( 'Expand trust indicator by user', function() { + browser.get(baseURL+"#/scenarios/test-scenario"); + var EC = browser.ExpectedConditions; + browser.wait(EC.urlContains(baseURL+ '#/scenarios/test-scenario'), 10000); + var installersShow = element(by.xpath('//*[@id="ng-app"]/body/div/div[1]/div/table/tbody/tr[4]/td[2]/div[1]/a/p')) + installersShow.click(); + var installerShow = element(by.xpath('//*[@id="ng-app"]/body/div/div[1]/div/table/tbody/tr[4]/td[2]/div[3]/div/table/tbody/tr[1]/td[2]/a')) + installerShow.click(); + var versionsShow = element(by.xpath('//*[@id="ng-app"]/body/div/div[1]/div/table/tbody/tr[4]/td[2]/div[3]/div/table/tbody/tr[2]/td[2]/div[1]/a/p')) + versionsShow.click(); + var versionShow = element(by.xpath('//*[@id="ng-app"]/body/div/div[1]/div/table/tbody/tr[4]/td[2]/div[3]/div/table/tbody/tr[2]/td[2]/div[3]/div/table/tbody/tr[1]/td[2]/a')) + versionShow.click() + var projectsShow = element(by.xpath('//*[@id="ng-app"]/body/div/div[1]/div/table/tbody/tr[4]/td[2]/div[3]/div/table/tbody/tr[2]/td[2]/div[3]/div/table/tbody/tr[3]/td[2]/div[1]/a')) + projectsShow.click(); + var projectShow = element(by.xpath('//*[@id="ng-app"]/body/div/div[1]/div/table/tbody/tr[4]/td[2]/div[3]/div/table/tbody/tr[2]/td[2]/div[3]/div/table/tbody/tr[3]/td[2]/div[3]/div/table/tbody/tr[1]/td[2]/a')) + projectShow.click(); + var trustIndicatorsShow = element(by.xpath('//*[@id="ng-app"]/body/div/div[1]/div/table/tbody/tr[4]/td[2]/div[3]/div/table/tbody/tr[2]/td[2]/div[3]/div/table/tbody/tr[3]/td[2]/div[3]/div/table/tbody/tr[2]/td[2]/a/p')) + trustIndicatorsShow.click(); + var row = element.all(by.repeater('(indexTI, trust_indicator) in project.trust_indicators')).first(); + var cells = row.all(by.tagName('td')); + expect(cells.get(1).getText()).toContain("silver"); + }); + + it( 'Expand score by user', function() { + browser.get(baseURL+"#/scenarios/test-scenario"); + var EC = browser.ExpectedConditions; + browser.wait(EC.urlContains(baseURL+ '#/scenarios/test-scenario'), 10000); + var installersShow = element(by.xpath('//*[@id="ng-app"]/body/div/div[1]/div/table/tbody/tr[4]/td[2]/div[1]/a/p')) + installersShow.click(); + var installerShow = element(by.xpath('//*[@id="ng-app"]/body/div/div[1]/div/table/tbody/tr[4]/td[2]/div[3]/div/table/tbody/tr[1]/td[2]/a')) + installerShow.click(); + var versionsShow = element(by.xpath('//*[@id="ng-app"]/body/div/div[1]/div/table/tbody/tr[4]/td[2]/div[3]/div/table/tbody/tr[2]/td[2]/div[1]/a/p')) + versionsShow.click(); + var versionShow = element(by.xpath('//*[@id="ng-app"]/body/div/div[1]/div/table/tbody/tr[4]/td[2]/div[3]/div/table/tbody/tr[2]/td[2]/div[3]/div/table/tbody/tr[1]/td[2]/a')) + versionShow.click() + var projectsShow = element(by.xpath('//*[@id="ng-app"]/body/div/div[1]/div/table/tbody/tr[4]/td[2]/div[3]/div/table/tbody/tr[2]/td[2]/div[3]/div/table/tbody/tr[3]/td[2]/div[1]/a')) + projectsShow.click(); + var projectShow = element(by.xpath('//*[@id="ng-app"]/body/div/div[1]/div/table/tbody/tr[4]/td[2]/div[3]/div/table/tbody/tr[2]/td[2]/div[3]/div/table/tbody/tr[3]/td[2]/div[3]/div/table/tbody/tr[1]/td[2]/a')) + projectShow.click(); + var scoresShow = element(by.xpath('//*[@id="ng-app"]/body/div/div[1]/div/table/tbody/tr[4]/td[2]/div[3]/div/table/tbody/tr[2]/td[2]/div[3]/div/table/tbody/tr[3]/td[2]/div[3]/div/table/tbody[1]/tr[3]/td[2]/a/p')) + scoresShow.click(); + var row = element.all(by.repeater('(indexSC, score) in project.scores')).first(); + var cells = row.all(by.tagName('td')); + expect(cells.get(1).getText()).toContain("14/24"); + }); + + it( 'Expand Customs by user', function() { + browser.get(baseURL+"#/scenarios/test-scenario"); + var EC = browser.ExpectedConditions; + browser.wait(EC.urlContains(baseURL+ '#/scenarios/test-scenario'), 10000); + var installersShow = element(by.xpath('//*[@id="ng-app"]/body/div/div[1]/div/table/tbody/tr[4]/td[2]/div[1]/a/p')) + installersShow.click(); + var installerShow = element(by.xpath('//*[@id="ng-app"]/body/div/div[1]/div/table/tbody/tr[4]/td[2]/div[3]/div/table/tbody/tr[1]/td[2]/a')) + installerShow.click(); + var versionsShow = element(by.xpath('//*[@id="ng-app"]/body/div/div[1]/div/table/tbody/tr[4]/td[2]/div[3]/div/table/tbody/tr[2]/td[2]/div[1]/a/p')) + versionsShow.click(); + var versionShow = element(by.xpath('//*[@id="ng-app"]/body/div/div[1]/div/table/tbody/tr[4]/td[2]/div[3]/div/table/tbody/tr[2]/td[2]/div[3]/div/table/tbody/tr[1]/td[2]/a')) + versionShow.click() + var projectsShow = element(by.xpath('//*[@id="ng-app"]/body/div/div[1]/div/table/tbody/tr[4]/td[2]/div[3]/div/table/tbody/tr[2]/td[2]/div[3]/div/table/tbody/tr[3]/td[2]/div[1]/a')) + projectsShow.click(); + var projectShow = element(by.xpath('//*[@id="ng-app"]/body/div/div[1]/div/table/tbody/tr[4]/td[2]/div[3]/div/table/tbody/tr[2]/td[2]/div[3]/div/table/tbody/tr[3]/td[2]/div[3]/div/table/tbody/tr[1]/td[2]/a')) + projectShow.click(); + var customsShow = element(by.xpath('//*[@id="ng-app"]/body/div/div[1]/div/table/tbody/tr[4]/td[2]/div[3]/div/table/tbody/tr[2]/td[2]/div[3]/div/table/tbody/tr[3]/td[2]/div[3]/div/table/tbody[1]/tr[4]/td[2]/a/p')) + customsShow.click(); + var row = element.all(by.repeater('(indexCU, custom) in project.customs')).first(); + var cells = row.all(by.tagName('td')); + expect(cells.get(0).getText()).toContain("dvs"); + var projectAdd = element(by.xpath('//*[@id="ng-app"]/body/div/div[1]/div/table/tbody/tr[4]/td[2]/div[3]/div/table/tbody/tr[2]/td[2]/div[3]/div/table/tbody/tr[3]/td[2]/div[2]/button')) + var projectDelete = element(by.xpath('//*[@id="ng-app"]/body/div/div[1]/div/table/tbody/tr[4]/td[2]/div[3]/div/table/tbody/tr[2]/td[2]/div[3]/div/table/tbody/tr[3]/td[2]/div[3]/div/table/tbody[1]/tr[1]/td[3]/button')) + expect(projectDelete.isDisplayed()).toBe(false) + expect(projectAdd.isDisplayed()).toBe(false) + var buttonAdd = element(by.xpath('//*[@id="ng-app"]/body/div/div[1]/div/table/tbody/tr[4]/td[2]/div[3]/div/table/tbody/tr[2]/td[2]/div[3]/div/table/tbody/tr[3]/td[2]/div[3]/div/table/tbody[1]/tr[4]/td[2]/button')) + var buttonDelete = element(by.xpath('//*[@id="ng-app"]/body/div/div[1]/div/table/tbody/tr[4]/td[2]/div[3]/div/table/tbody/tr[2]/td[2]/div[3]/div/table/tbody/tr[3]/td[2]/div[3]/div/table/tbody[1]/tr[4]/td[2]/table/tbody/tr[1]/td[2]/button')) + expect(buttonAdd.isDisplayed()).toBe(true) + expect(buttonDelete.isDisplayed()).toBe(true) + }); + + it( 'Add Customs by user', function() { + browser.get(baseURL+"#/scenarios/test-scenario"); + var EC = browser.ExpectedConditions; + browser.wait(EC.urlContains(baseURL+ '#/scenarios/test-scenario'), 10000); + var installersShow = element(by.xpath('//*[@id="ng-app"]/body/div/div[1]/div/table/tbody/tr[4]/td[2]/div[1]/a/p')) + installersShow.click(); + var installerShow = element(by.xpath('//*[@id="ng-app"]/body/div/div[1]/div/table/tbody/tr[4]/td[2]/div[3]/div/table/tbody/tr[1]/td[2]/a')) + installerShow.click(); + var versionsShow = element(by.xpath('//*[@id="ng-app"]/body/div/div[1]/div/table/tbody/tr[4]/td[2]/div[3]/div/table/tbody/tr[2]/td[2]/div[1]/a/p')) + versionsShow.click(); + var versionShow = element(by.xpath('//*[@id="ng-app"]/body/div/div[1]/div/table/tbody/tr[4]/td[2]/div[3]/div/table/tbody/tr[2]/td[2]/div[3]/div/table/tbody/tr[1]/td[2]/a')) + versionShow.click() + var projectsShow = element(by.xpath('//*[@id="ng-app"]/body/div/div[1]/div/table/tbody/tr[4]/td[2]/div[3]/div/table/tbody/tr[2]/td[2]/div[3]/div/table/tbody/tr[3]/td[2]/div[1]/a')) + projectsShow.click(); + var projectShow = element(by.xpath('//*[@id="ng-app"]/body/div/div[1]/div/table/tbody/tr[4]/td[2]/div[3]/div/table/tbody/tr[2]/td[2]/div[3]/div/table/tbody/tr[3]/td[2]/div[3]/div/table/tbody/tr[1]/td[2]/a')) + projectShow.click(); + var customsShow = element(by.xpath('//*[@id="ng-app"]/body/div/div[1]/div/table/tbody/tr[4]/td[2]/div[3]/div/table/tbody/tr[2]/td[2]/div[3]/div/table/tbody/tr[3]/td[2]/div[3]/div/table/tbody[1]/tr[4]/td[2]/a/p')) + customsShow.click(); + var row = element.all(by.repeater('(indexCU, custom) in project.customs')).first(); + var cells = row.all(by.tagName('td')); + expect(cells.get(0).getText()).toContain("dvs"); + var buttonAdd = element(by.xpath('//*[@id="ng-app"]/body/div/div[1]/div/table/tbody/tr[4]/td[2]/div[3]/div/table/tbody/tr[2]/td[2]/div[3]/div/table/tbody/tr[3]/td[2]/div[3]/div/table/tbody[1]/tr[4]/td[2]/button')) + buttonAdd.click() + var custom = element(by.model('customModalCtrl.custom')); + browser.wait(EC.visibilityOf(custom), 5000); + custom.sendKeys('testC'); + var buttonOk = element(by.xpath('//*[@id="ng-app"]/body/div[3]/div/div/div/div[2]/button[1]')) + buttonOk.click() + expect(element(by.cssContainingText(".alert","Customs are successfully updated.")) + .isDisplayed()).toBe(true); + }); + + it( 'Delete Customs by user', function() { + browser.get(baseURL+"#/scenarios/test-scenario"); + var EC = browser.ExpectedConditions; + browser.wait(EC.urlContains(baseURL+ '#/scenarios/test-scenario'), 10000); + var installersShow = element(by.xpath('//*[@id="ng-app"]/body/div/div[1]/div/table/tbody/tr[4]/td[2]/div[1]/a/p')) + installersShow.click(); + var installerShow = element(by.xpath('//*[@id="ng-app"]/body/div/div[1]/div/table/tbody/tr[4]/td[2]/div[3]/div/table/tbody/tr[1]/td[2]/a')) + installerShow.click(); + var versionsShow = element(by.xpath('//*[@id="ng-app"]/body/div/div[1]/div/table/tbody/tr[4]/td[2]/div[3]/div/table/tbody/tr[2]/td[2]/div[1]/a/p')) + versionsShow.click(); + var versionShow = element(by.xpath('//*[@id="ng-app"]/body/div/div[1]/div/table/tbody/tr[4]/td[2]/div[3]/div/table/tbody/tr[2]/td[2]/div[3]/div/table/tbody/tr[1]/td[2]/a')) + versionShow.click() + var projectsShow = element(by.xpath('//*[@id="ng-app"]/body/div/div[1]/div/table/tbody/tr[4]/td[2]/div[3]/div/table/tbody/tr[2]/td[2]/div[3]/div/table/tbody/tr[3]/td[2]/div[1]/a')) + projectsShow.click(); + var projectShow = element(by.xpath('//*[@id="ng-app"]/body/div/div[1]/div/table/tbody/tr[4]/td[2]/div[3]/div/table/tbody/tr[2]/td[2]/div[3]/div/table/tbody/tr[3]/td[2]/div[3]/div/table/tbody/tr[1]/td[2]/a')) + projectShow.click(); + var customsShow = element(by.xpath('//*[@id="ng-app"]/body/div/div[1]/div/table/tbody/tr[4]/td[2]/div[3]/div/table/tbody/tr[2]/td[2]/div[3]/div/table/tbody/tr[3]/td[2]/div[3]/div/table/tbody[1]/tr[4]/td[2]/a/p')) + customsShow.click(); + var row = element.all(by.repeater('(indexCU, custom) in project.customs')).first(); + var cells = row.all(by.tagName('td')); + expect(cells.get(0).getText()).toContain("dvs"); + var buttonAdd = element(by.xpath('//*[@id="ng-app"]/body/div/div[1]/div/table/tbody/tr[4]/td[2]/div[3]/div/table/tbody/tr[2]/td[2]/div[3]/div/table/tbody/tr[3]/td[2]/div[3]/div/table/tbody[1]/tr[4]/td[2]/table/tbody/tr[1]/td[2]/button')) + buttonAdd.click() + var buttonOk = element(by.xpath('//*[@id="ng-app"]/body/div[3]/div/div/div[3]/button[1]')) + buttonOk.click() + expect(element(by.cssContainingText(".alert","Customs are successfully deleted.")) + .isDisplayed()).toBe(true); + }); + +});
\ No newline at end of file diff --git a/testapi/opnfv_testapi/tests/UI/e2e/scenariosControllerSpec.js b/testapi/opnfv_testapi/tests/UI/e2e/scenariosControllerSpec.js new file mode 100644 index 0000000..505b42f --- /dev/null +++ b/testapi/opnfv_testapi/tests/UI/e2e/scenariosControllerSpec.js @@ -0,0 +1,725 @@ +'use strict'; + +var mock = require('protractor-http-mock'); +var baseURL = "http://localhost:8000/" + +describe('testing the scenarios page for anonymous user', function () { + beforeEach(function(){ + mock([ + { + request: { + path: '/api/v1/scenarios', + method: 'GET' + }, + response: { + data: { + "scenarios": [ + { + "installers": [ + { + "installer": "fuel", + "versions": [ + { + "owner": "testUser", + "version": "colorado", + "projects": [ + { + "project": "yardstick", + "customs": [ + "dvs" + ], + "scores": [ + { + "date": "2016-12-11 01:45", + "score": "14/24" + }, + { + "date": "2016-12-15 05:28", + "score": "17/24" + }, + { + "date": "2016-12-17 03:41", + "score": "16/24" + }, + { + "date": "2018-01-22T18:30:00.000Z", + "score": "10/13" + } + ], + "trust_indicators": [ + { + "date": "2016-12-09 11:38", + "status": "silver" + }, + { + "date": "2016-12-25 08:22", + "status": "gold" + }, + { + "date": "2018-01-22T18:30:00.000Z", + "status": "sf" + }, + { + "date": "2018-01-17T18:30:00.000Z", + "status": "df" + } + ] + }, + { + "project": "functest", + "customs": [ + "vping_ssh", + "vping_userdata", + ], + "scores": [ + { + "date": "2016-12-09 11:28", + "score": "6/8" + }, + { + "date": "2016-12-14 15:34", + "score": "8/8" + }, + { + "date": "2016-12-19 13:22", + "score": "8/8" + }, + { + "date": "2016-12-22 18:17", + "score": "8/8" + }, + { + "date": "2016-12-25 08:22", + "score": "8/8" + } + ], + "trust_indicators": [ + { + "date": "2016-12-09 11:38", + "status": "silver" + } + ] + }, + { + "project": "sla", + "customs": [], + "scores": [ + { + "date": "2018-01-16T18:30:00.000Z", + "score": "sdS" + } + ], + "trust_indicators": [] + }, + { + "project": "dvsd", + "customs": [], + "scores": [], + "trust_indicators": [] + } + ] + }, + { + "owner": "dfgvds", + "version": "df", + "projects": [] + } + ] + }, + { + "installer": "fuel2", + "versions": [ + { + "owner": "testUser", + "version": "colorado", + "projects": [ + { + "project": "yardstick", + "customs": [ + "tc002", + "tc005", + "tc010", + "tc011" + ], + "scores": [ + { + "date": "2016-12-11 01:45", + "score": "14/24" + }, + { + "date": "2016-12-15 05:28", + "score": "17/24" + }, + { + "date": "2016-12-17 03:41", + "score": "16/24" + } + ], + "trust_indicators": [ + { + "date": "2016-12-09 11:38", + "status": "silver" + }, + { + "date": "2016-12-25 08:22", + "status": "gold" + } + ] + }, + { + "project": "functest", + "customs": [ + "vping_ssh", + "vping_userdata" + ], + "scores": [ + { + "date": "2016-12-09 11:28", + "score": "6/8" + }, + { + "date": "2016-12-14 15:34", + "score": "8/8" + } + ], + "trust_indicators": [ + { + "date": "2016-12-09 11:38", + "status": "silver" + } + ] + } + ] + } + ] + } + ], + "_id": "5a50fcacsdgdsgdasgfvb861c", + "name": "test-scenario", + "creation_date": "2018-01-06 22:13:24.160407" + } + ] + } + } + } + ]); + }); + + afterEach(function(){ + mock.teardown(); + }); + + it( 'should show the scenarios page for anonymous user', function() { + browser.get(baseURL+"#/scenarios"); + var EC = browser.ExpectedConditions; + browser.wait(EC.urlContains(baseURL+ '#/scenarios'), 10000); + }); + + it( 'navigate anonymous user to scenarios page', function() { + browser.get(baseURL); + var resultLink = element(by.linkText('Scenarios')).click(); + var EC = browser.ExpectedConditions; + browser.wait(EC.urlContains(baseURL+ '#/scenarios'), 10000); + }); + + it('Should show the scenarios in scenarios page for anonymous user ', function () { + browser.get(baseURL+"#/scenarios"); + var row = element.all(by.repeater('(index, scenario) in ctrl.data.scenarios')).first(); + var cells = row.all(by.tagName('td')); + expect(cells.get(1).getText()).toContain("test-scenario"); + }); + + it('create button is not visible for anonymous user ', function () { + browser.get(baseURL+'#/scenarios'); + var buttonCreate = element(by.buttonText('Create')); + expect(buttonCreate.isDisplayed()).toBeFalsy(); + }); + it('delete button is not visible for anonymous user ', function () { + browser.get(baseURL+'#/scenarios'); + var buttonCreate = element(by.buttonText('Delete')); + expect(buttonCreate.isDisplayed()).toBeFalsy(); + }); + +}); + +describe('testing the scenarios page for user', function () { + beforeEach(function(){ + mock([ + { + request: { + path: '/api/v1/scenarios', + method: 'GET' + }, + response: { + data: { + "scenarios": [ + { + "installers": [ + { + "installer": "fuel", + "versions": [ + { + "owner": "testUser", + "version": "colorado", + "projects": [ + { + "project": "yardstick", + "customs": [ + "dvs" + ], + "scores": [ + { + "date": "2016-12-11 01:45", + "score": "14/24" + }, + { + "date": "2016-12-15 05:28", + "score": "17/24" + }, + { + "date": "2016-12-17 03:41", + "score": "16/24" + }, + { + "date": "2018-01-22T18:30:00.000Z", + "score": "10/13" + } + ], + "trust_indicators": [ + { + "date": "2016-12-09 11:38", + "status": "silver" + }, + { + "date": "2016-12-25 08:22", + "status": "gold" + }, + { + "date": "2018-01-22T18:30:00.000Z", + "status": "sf" + }, + { + "date": "2018-01-17T18:30:00.000Z", + "status": "df" + } + ] + }, + { + "project": "functest", + "customs": [ + "vping_ssh", + "vping_userdata", + ], + "scores": [ + { + "date": "2016-12-09 11:28", + "score": "6/8" + }, + { + "date": "2016-12-14 15:34", + "score": "8/8" + }, + { + "date": "2016-12-19 13:22", + "score": "8/8" + }, + { + "date": "2016-12-22 18:17", + "score": "8/8" + }, + { + "date": "2016-12-25 08:22", + "score": "8/8" + } + ], + "trust_indicators": [ + { + "date": "2016-12-09 11:38", + "status": "silver" + } + ] + }, + { + "project": "sla", + "customs": [], + "scores": [ + { + "date": "2018-01-16T18:30:00.000Z", + "score": "sdS" + } + ], + "trust_indicators": [] + }, + { + "project": "dvsd", + "customs": [], + "scores": [], + "trust_indicators": [] + } + ] + }, + { + "owner": "dfgvds", + "version": "df", + "projects": [] + } + ] + }, + { + "installer": "fuel2", + "versions": [ + { + "owner": "testUser", + "version": "colorado", + "projects": [ + { + "project": "yardstick", + "customs": [ + "tc002", + "tc005", + "tc010", + "tc011" + ], + "scores": [ + { + "date": "2016-12-11 01:45", + "score": "14/24" + }, + { + "date": "2016-12-15 05:28", + "score": "17/24" + }, + { + "date": "2016-12-17 03:41", + "score": "16/24" + } + ], + "trust_indicators": [ + { + "date": "2016-12-09 11:38", + "status": "silver" + }, + { + "date": "2016-12-25 08:22", + "status": "gold" + } + ] + }, + { + "project": "functest", + "customs": [ + "vping_ssh", + "vping_userdata" + ], + "scores": [ + { + "date": "2016-12-09 11:28", + "score": "6/8" + }, + { + "date": "2016-12-14 15:34", + "score": "8/8" + } + ], + "trust_indicators": [ + { + "date": "2016-12-09 11:38", + "status": "silver" + } + ] + } + ] + } + ] + } + ], + "_id": "5a50fcacsdgdsgdasgfvb861c", + "name": "test-scenario", + "creation_date": "2018-01-06 22:13:24.160407" + } + ] + } + } + }, + { + request: { + path: '/api/v1/profile', + method: 'GET' + }, + response: { + data: { + "fullname": "Test User", "_id": "79f82eey9a00c84bfhc7aed", + "user": "testUser", "groups": ["opnfv-testapi-users"], + "email": "testuser@test.com" + } + } + }, + { + request: { + path: '/api/v1/scenarios', + method: 'POST' + }, + response: { + data: { + href: baseURL+"/api/v1/scenarios/testScenario" + } + } + }, + { + request: { + path: '/api/v1/scenarios/test-scenario', + method: 'DELETE' + }, + response: { + data: { + href: baseURL+"/api/v1/scenarios/testScenario" + } + } + }, + { + request: { + path: '/api/v1/scenarios/test-scenario', + method: 'PUT' + }, + response: { + data: { + href: baseURL+"/api/v1/scenarios/testScenario" + } + } + } + ]); + }); + + afterEach(function(){ + mock.teardown(); + }); + + it( 'should show the scenarios page for user', function() { + browser.get(baseURL+"#/scenarios"); + var EC = browser.ExpectedConditions; + browser.wait(EC.urlContains(baseURL+ '#/scenarios'), 10000); + }); + + it( 'navigate user to scenarios page', function() { + browser.get(baseURL); + var resultLink = element(by.linkText('Scenarios')).click(); + var EC = browser.ExpectedConditions; + browser.wait(EC.urlContains(baseURL+ '#/scenarios'), 10000); + }); + + it('Should show the scenarios in scenarios page for user ', function () { + browser.get(baseURL+"#/scenarios"); + var row = element.all(by.repeater('(index, scenario) in ctrl.data.scenarios')).first(); + var cells = row.all(by.tagName('td')); + expect(cells.get(1).getText()).toContain("test-scenario"); + }); + + it('create button is not visible for user ', function () { + browser.get(baseURL+'#/scenarios'); + var buttonCreate = element(by.buttonText('Create')); + expect(buttonCreate.isDisplayed()).toBe(true); + }); + + it('delete button is not visible for user ', function () { + browser.get(baseURL+'#/scenarios'); + var buttonDelete = element(by.buttonText('Delete')); + expect(buttonDelete.isDisplayed()).toBe(true); + }); + + it('craete scenarrio by user without installers ', function () { + browser.get(baseURL+'#/scenarios'); + var buttonCreate = element(by.buttonText('Create')).click(); + var name = element(by.model('scenarioModalController.scenario.name')); + var EC = browser.ExpectedConditions; + browser.wait(EC.visibilityOf(name), 5000); + name.sendKeys('test'); + var buttonOK = element(by.buttonText('Ok')); + buttonOK.click(); + expect(element(by.cssContainingText(".alert","Scenario is successfully created.")) + .isDisplayed()).toBe(true); + }); + + it('create scenarrio by user with installers ', function () { + browser.get(baseURL+'#/scenarios'); + var buttonCreate = element(by.buttonText('Create')).click(); + var name = element(by.model('scenarioModalController.scenario.name')); + var EC = browser.ExpectedConditions; + browser.wait(EC.visibilityOf(name), 5000); + name.sendKeys('test'); + var buttonInstaller = element(by.xpath('//*[@id="ng-app"]/body/div[3]/div/div/div/div[1]/div[1]/fieldset/div/div/div[2]/div[2]/button')) + buttonInstaller.click(); + var installer = element(by.model('installerModalCtrl.installer.installer')); + browser.wait(EC.visibilityOf(installer), 5000); + installer.sendKeys('testI'); + var buttonOK = element(by.xpath('//*[@id="ng-app"]/body/div[4]/div/div/div/div[2]/button[1]')); + buttonOK.click(); + var buttonOK = element(by.buttonText('Ok')); + buttonOK.click(); + expect(element(by.cssContainingText(".alert","Scenario is successfully created.")) + .isDisplayed()).toBe(true); + }); + + it('create scenarrio by user with installers with versions ', function () { + browser.get(baseURL+'#/scenarios'); + var buttonCreate = element(by.buttonText('Create')).click(); + var name = element(by.model('scenarioModalController.scenario.name')); + var EC = browser.ExpectedConditions; + browser.wait(EC.visibilityOf(name), 5000); + name.sendKeys('test'); + var buttonInstaller = element(by.xpath('//*[@id="ng-app"]/body/div[3]/div/div/div/div[1]/div[1]/fieldset/div/div/div[2]/div[2]/button')) + buttonInstaller.click(); + var installer = element(by.model('installerModalCtrl.installer.installer')); + browser.wait(EC.visibilityOf(installer), 5000); + installer.sendKeys('testI'); + var buttonVersion = element(by.xpath('//*[@id="ng-app"]/body/div[4]/div/div/div/div[1]/div[1]/fieldset/div/div/div[2]/div[2]/button')) + buttonVersion.click(); + var version = element(by.model('versionModalCtrl.version.version')); + browser.wait(EC.visibilityOf(version), 5000); + version.sendKeys('testV'); + var owner = element(by.model('versionModalCtrl.version.owner')); + owner.sendKeys('testOwner'); + var buttonOK = element(by.xpath('//*[@id="ng-app"]/body/div[5]/div/div/div/div[2]/button[1]')); + buttonOK.click(); + var buttonOK = element(by.xpath('//*[@id="ng-app"]/body/div[4]/div/div/div/div[2]/button[1]')); + buttonOK.click(); + var buttonOK = element(by.buttonText('Ok')); + buttonOK.click(); + expect(element(by.cssContainingText(".alert","Scenario is successfully created.")) + .isDisplayed()).toBe(true); + }); + + it('create scenarrio by user with installers with versions with project', function () { + browser.get(baseURL+'#/scenarios'); + var buttonCreate = element(by.buttonText('Create')).click(); + var name = element(by.model('scenarioModalController.scenario.name')); + var EC = browser.ExpectedConditions; + browser.wait(EC.visibilityOf(name), 5000); + name.sendKeys('test'); + var buttonInstaller = element(by.xpath('//*[@id="ng-app"]/body/div[3]/div/div/div/div[1]/div[1]/fieldset/div/div/div[2]/div[2]/button')) + buttonInstaller.click(); + var installer = element(by.model('installerModalCtrl.installer.installer')); + browser.wait(EC.visibilityOf(installer), 5000); + installer.sendKeys('testI'); + var buttonVersion = element(by.xpath('//*[@id="ng-app"]/body/div[4]/div/div/div/div[1]/div[1]/fieldset/div/div/div[2]/div[2]/button')) + buttonVersion.click(); + var version = element(by.model('versionModalCtrl.version.version')); + browser.wait(EC.visibilityOf(version), 5000); + version.sendKeys('testV'); + var owner = element(by.model('versionModalCtrl.version.owner')); + owner.sendKeys('testOwner'); + var buttonProject = element(by.xpath('//*[@id="ng-app"]/body/div[5]/div/div/div/div[1]/div[1]/fieldset/div/div/div[3]/div[2]/button')) + buttonProject.click(); + var project = element(by.model('projectModalCtrl.project.project')); + browser.wait(EC.visibilityOf(project), 5000); + project.sendKeys('testP'); + var buttonOK = element(by.xpath('//*[@id="ng-app"]/body/div[6]/div/div/div/div[2]/button[1]')); + buttonOK.click(); + var buttonOK = element(by.xpath('//*[@id="ng-app"]/body/div[5]/div/div/div/div[2]/button[1]')); + buttonOK.click(); + var buttonOK = element(by.xpath('//*[@id="ng-app"]/body/div[4]/div/div/div/div[2]/button[1]')); + buttonOK.click(); + var buttonOK = element(by.buttonText('Ok')); + buttonOK.click(); + expect(element(by.cssContainingText(".alert","Scenario is successfully created.")) + .isDisplayed()).toBe(true); + }); + + it('create scenarrio by user with installers with versions with project with custom', function () { + browser.get(baseURL+'#/scenarios'); + var buttonCreate = element(by.buttonText('Create')).click(); + var name = element(by.model('scenarioModalController.scenario.name')); + var EC = browser.ExpectedConditions; + browser.wait(EC.visibilityOf(name), 5000); + name.sendKeys('test'); + var buttonInstaller = element(by.xpath('//*[@id="ng-app"]/body/div[3]/div/div/div/div[1]/div[1]/fieldset/div/div/div[2]/div[2]/button')) + buttonInstaller.click(); + var installer = element(by.model('installerModalCtrl.installer.installer')); + browser.wait(EC.visibilityOf(installer), 5000); + installer.sendKeys('testI'); + var buttonVersion = element(by.xpath('//*[@id="ng-app"]/body/div[4]/div/div/div/div[1]/div[1]/fieldset/div/div/div[2]/div[2]/button')) + buttonVersion.click(); + var version = element(by.model('versionModalCtrl.version.version')); + browser.wait(EC.visibilityOf(version), 5000); + version.sendKeys('testV'); + var owner = element(by.model('versionModalCtrl.version.owner')); + owner.sendKeys('testOwner'); + var buttonProject = element(by.xpath('//*[@id="ng-app"]/body/div[5]/div/div/div/div[1]/div[1]/fieldset/div/div/div[3]/div[2]/button')) + buttonProject.click(); + var project = element(by.model('projectModalCtrl.project.project')); + browser.wait(EC.visibilityOf(project), 5000); + project.sendKeys('testP'); + var buttonCustom = element(by.xpath('//*[@id="ng-app"]/body/div[6]/div/div/div/div[1]/div[1]/fieldset/div/div/div[2]/div[2]/button')) + buttonCustom.click(); + var custom = element(by.model('customModalCtrl.custom')); + browser.wait(EC.visibilityOf(custom), 5000); + custom.sendKeys('testC'); + var buttonOK = element(by.xpath('//*[@id="ng-app"]/body/div[7]/div/div/div/div[2]/button[1]')); + buttonOK.click(); + var buttonOK = element(by.xpath('//*[@id="ng-app"]/body/div[6]/div/div/div/div[2]/button[1]')); + buttonOK.click(); + var buttonOK = element(by.xpath('//*[@id="ng-app"]/body/div[5]/div/div/div/div[2]/button[1]')); + buttonOK.click(); + var buttonOK = element(by.xpath('//*[@id="ng-app"]/body/div[4]/div/div/div/div[2]/button[1]')); + buttonOK.click(); + var buttonOK = element(by.buttonText('Ok')); + buttonOK.click(); + expect(element(by.cssContainingText(".alert","Scenario is successfully created.")) + .isDisplayed()).toBe(true); + }); + + it('view scenarrio by user ', function () { + browser.get(baseURL+'#/scenarios'); + var scenarioLink = element(by.linkText('test-scenario')).click(); + var EC = browser.ExpectedConditions; + browser.wait(EC.urlContains(baseURL+ '#/scenarios/test-scenario'), 10000); + }); + + it('delete Operation is visible for user ', function () { + browser.get(baseURL+'#/scenarios'); + var deleteOperation = element(by.css('a[title=Delete]')); + expect(deleteOperation.isDisplayed()).toBe(true); + }); + + it('edit Operation is visible for user ', function () { + browser.get(baseURL+'#/scenarios'); + var deleteOperation = element(by.css('a[title=Edit]')); + expect(deleteOperation.isDisplayed()).toBe(true); + }); + + it('Delete the Scenario ', function () { + browser.get(baseURL+'#/scenarios'); + var deleteOperation = element(by.css('a[title=Delete]')); + deleteOperation.click(); + var buttonOK = element(by.buttonText('Ok')); + buttonOK.click(); + expect(element(by.cssContainingText(".alert","Scenario is successfully deleted.")) + .isDisplayed()).toBe(true); + }); + + it('Batch Delete the scenarios ', function () { + browser.get(baseURL+'#/scenarios'); + var checkBox = element(by.model('ctrl.checkBox[index]')); + checkBox.click(); + var buttonDelete = element(by.buttonText('Delete'));; + buttonDelete.click(); + var buttonOK = element(by.buttonText('Ok')); + buttonOK.click(); + expect(element(by.cssContainingText(".alert","Scenario is successfully deleted.")) + .isDisplayed()).toBe(true); + }); + + it('Edit the scenarios ', function () { + browser.get(baseURL+'#/scenarios'); + var editOperation = element(by.css('a[title=Edit]')); + editOperation.click(); + var name = element(by.model('ScenarioNameUpdateCtrl.name')); + var EC = browser.ExpectedConditions; + browser.wait(EC.visibilityOf(name), 5000); + name.sendKeys('test2'); + var buttonOK = element(by.buttonText('Ok')); + buttonOK.click() + expect(element(by.cssContainingText(".alert","Scenario is successfully Updated.")) + .isDisplayed()).toBe(true); + }); + +});
\ No newline at end of file diff --git a/testapi/opnfv_testapi/tests/UI/e2e/testCasesControllerSpec.js b/testapi/opnfv_testapi/tests/UI/e2e/testCasesControllerSpec.js new file mode 100644 index 0000000..d509c57 --- /dev/null +++ b/testapi/opnfv_testapi/tests/UI/e2e/testCasesControllerSpec.js @@ -0,0 +1,650 @@ +'use strict'; + +var mock = require('protractor-http-mock'); +var baseURL = "http://localhost:8000/" + +describe('testing the testCases page for anonymous user', function () { + beforeEach(function(){ + mock([ + { + request: { + path: '/api/v1/projects', + method: 'GET' + }, + response: { + data: { + "projects": [ + { + "owner": "thuva4", + "_id": "5a0c022f9a07c846d3c2cc94", + "creation_date": "2017-11-15 14:30:31.200259", + "description": "dsfsd", + "name": "testproject" + } + ] + } + } + }, + { + request: { + path: '/api/v1/projects/testproject', + method: 'GET' + }, + response: { + data: { + "owner": "thuva4", + "_id": "5a0c022f9a07c846d3c2cc94", + "creation_date": "2017-11-15 14:30:31.200259", + "description": "dsfsd", + "name": "testproject" + } + } + }, + { + request: { + path: '/api/v1/projects/testproject/cases', + method: 'GET' + }, + response: { + data: { + "testcases": [ + { + "project_name": "testproject", + "run": null, + "description": null, + "tags": null, + "creation_date": "2017-12-20 18:47:04.025544", + "dependencies": null, + "tier": null, + "trust": null, + "blocking": null, + "name": "testCase", + "ci_loop": null, + "url": null, + "version": null, + "criteria": null, + "domains": null, + "_id": "5a3a62d09a07c836e06858fb", + "catalog_description": null + } + ] + } + } + }, + { + request: { + path: '/api/v1/projects/testproject/cases/testCase', + method: 'GET' + }, + response: { + data: { + "project_name": "testproject", + "run": null, + "description": null, + "tags": null, + "creation_date": "2017-12-20 18:47:04.025544", + "dependencies": null, + "tier": null, + "trust": null, + "blocking": null, + "name": "testCase", + "ci_loop": null, + "url": null, + "version": null, + "criteria": null, + "domains": null, + "_id": "5a3a62d09a07c836e06858fb", + "catalog_description": null + } + } + } + ]); + }); + + afterEach(function(){ + mock.teardown(); + }); + + it( 'should show the testCases for anonymous user', function() { + browser.get(baseURL+"#/projects/testproject"); + var testCases = element(by.linkText('Test Cases')); + testCases.click(); + var row = element.all(by.repeater('(index, testcase) in testCasesCtrl.data.testcases')).first(); + var cells = row.all(by.tagName('td')); + expect(cells.get(1).getText()).toContain("testCase"); + }); + + it( 'navigate anonymous user to testCase page', function() { + browser.get(baseURL+"#/projects/testproject"); + var testCases = element(by.linkText('Test Cases')); + testCases.click(); + var testCase = element(by.linkText('testCase')); + testCase.click(); + var EC = browser.ExpectedConditions; + browser.wait(EC.urlContains(baseURL+ '#/projects/testproject/testCase'), 10000); + }); + + it('create button is not visible for anonymous user ', function () { + browser.get(baseURL+"#/projects/testproject"); + var testCases = element(by.linkText('Test Cases')); + testCases.click(); + var buttonCreate = element(by.buttonText('Create')); + expect(buttonCreate.isDisplayed()).toBeFalsy(); + }); + + it('Delete button is not visible for anonymous user ', function () { + browser.get(baseURL+"#/projects/testproject"); + var testCases = element(by.linkText('Test Cases')); + testCases.click(); + var buttonDelete = element(by.buttonText('Delete')); + expect(buttonDelete.isDisplayed()).toBeFalsy(); + }); + + it('delete Operation is not visible for anonymous user ', function () { + browser.get(baseURL+"#/projects/testproject"); + var testCases = element(by.linkText('Test Cases')); + testCases.click(); + var deleteOperation = element(by.css('a[title=Delete]')); + expect(deleteOperation.isDisplayed()).toBeFalsy(); + }); + + it('Edit Operation is not visible for anonymous user ', function () { + browser.get(baseURL+"#/projects/testproject"); + var testCases = element(by.linkText('Test Cases')); + testCases.click(); + var editOperation = element(by.css('a[title=Edit]')); + expect(editOperation.isDisplayed()).toBeFalsy(); + }); +}); + +describe('testing the testcaese page for user who is not in submitter group', function () { + beforeEach(function(){ + mock([ + { + request: { + path: '/api/v1/profile', + method: 'GET' + }, + response: { + data: { + "fullname": "Test User", "_id": "79f82eey9a00c84bfhc7aed", + "user": "testUser", "groups": ["opnfv-testapi-users"], + "email": "testuser@test.com" + } + } + }, + { + request: { + path: '/api/v1/projects', + method: 'GET' + }, + response: { + data: { + "projects": [ + { + "owner": "thuva4", + "_id": "5a0c022f9a07c846d3c2cc94", + "creation_date": "2017-11-15 14:30:31.200259", + "description": "dsfsd", + "name": "testproject" + } + ] + } + } + }, + { + request: { + path: '/api/v1/projects/testproject', + method: 'GET' + }, + response: { + data: { + "owner": "thuva4", + "_id": "5a0c022f9a07c846d3c2cc94", + "creation_date": "2017-11-15 14:30:31.200259", + "description": "dsfsd", + "name": "testproject" + } + } + }, + { + request: { + path: '/api/v1/projects/testproject/cases', + method: 'GET' + }, + response: { + data: { + "testcases": [ + { + "project_name": "testproject", + "run": null, + "description": null, + "tags": null, + "creation_date": "2017-12-20 18:47:04.025544", + "dependencies": null, + "tier": null, + "trust": null, + "blocking": null, + "name": "testCase", + "ci_loop": null, + "url": null, + "version": null, + "criteria": null, + "domains": null, + "_id": "5a3a62d09a07c836e06858fb", + "catalog_description": null + } + ] + } + } + }, + { + request: { + path: '/api/v1/projects/testproject/cases/testCase', + method: 'GET' + }, + response: { + data: { + "project_name": "testproject", + "run": null, + "description": null, + "tags": null, + "creation_date": "2017-12-20 18:47:04.025544", + "dependencies": null, + "tier": null, + "trust": null, + "blocking": null, + "name": "testCase", + "ci_loop": null, + "url": null, + "version": null, + "criteria": null, + "domains": null, + "_id": "5a3a62d09a07c836e06858fb", + "catalog_description": null + } + } + } + ]); + }); + + afterEach(function(){ + mock.teardown(); + }); + + it( 'should show the testCases for user', function() { + browser.get(baseURL+"#/projects/testproject"); + var testCases = element(by.linkText('Test Cases')); + testCases.click(); + var row = element.all(by.repeater('(index, testcase) in testCasesCtrl.data.testcases')).first(); + var cells = row.all(by.tagName('td')); + expect(cells.get(1).getText()).toContain("testCase"); + }); + + it( 'navigate user to testCase page', function() { + browser.get(baseURL+"#/projects/testproject"); + var testCases = element(by.linkText('Test Cases')); + testCases.click(); + var testCase = element(by.linkText('testCase')); + testCase.click(); + var EC = browser.ExpectedConditions; + browser.wait(EC.urlContains(baseURL+ '#/projects/testproject/testCase'), 10000); + }); + + it('create button is not visible for user ', function () { + browser.get(baseURL+"#/projects/testproject"); + var testCases = element(by.linkText('Test Cases')); + testCases.click(); + var buttonCreate = element(by.buttonText('Create')); + expect(buttonCreate.isDisplayed()).toBeFalsy(); + }); + + it('Delete button is not visible for user ', function () { + browser.get(baseURL+"#/projects/testproject"); + var testCases = element(by.linkText('Test Cases')); + testCases.click(); + var buttonDelete = element(by.buttonText('Delete')); + expect(buttonDelete.isDisplayed()).toBeFalsy(); + }); + + it('delete Operation is not visible for user ', function () { + browser.get(baseURL+"#/projects/testproject"); + var testCases = element(by.linkText('Test Cases')); + testCases.click(); + var deleteOperation = element(by.css('a[title=Delete]')); + expect(deleteOperation.isDisplayed()).toBeFalsy(); + }); + + it('Edit Operation is not visible for user ', function () { + browser.get(baseURL+"#/projects/testproject"); + var testCases = element(by.linkText('Test Cases')); + testCases.click(); + var editOperation = element(by.css('a[title=Edit]')); + expect(editOperation.isDisplayed()).toBeFalsy(); + }); +}) + +describe('testing the test cases page for user who is in submitter group', function () { + beforeEach(function(){ + mock([ + { + request: { + path: '/api/v1/profile', + method: 'GET' + }, + response: { + data: { + "fullname": "Test User", "_id": "79f82eey9a00c84bfhc7aed", + "user": "testUser", "groups": ["opnfv-testapi-users", + "opnfv-gerrit-testProject-submitters"], + "email": "testuser@test.com" + } + } + }, + { + request: { + path: '/api/v1/projects/testproject/cases', + method: 'POST' + }, + response: { + data: { + href: baseURL+"/api/v1/projects/testProject/cases/testCase" + } + } + }, + { + request: { + path: '/api/v1/projects/testproject/cases/testCase', + method: 'PUT' + }, + response: { + data: { + href: baseURL+"/api/v1/projects/testProject/cases/testCase" + } + } + }, + { + request: { + path: '/api/v1/projects/testproject/cases/testCase', + method: 'DELETE' + }, + response: { + data: { + href: baseURL+"/api/v1/projects/testProject/cases/testCase" + } + } + }, + { + request: { + path: '/api/v1/projects/testProject3/cases', + method: 'POST', + data: { + name: 'testCase2', + description : 'demoDescription', + } + }, + response: { + status : 403, + data : 'You do not have permission to perform this action' + } + }, + { + request: { + path: '/api/v1/projects', + method: 'GET' + }, + response: { + data: { + "projects": [ + { + "owner": "thuva4", + "_id": "5a0c022f9a07c846d3c2cc94", + "creation_date": "2017-11-15 14:30:31.200259", + "description": "dsfsd", + "name": "testproject" + } + ] + } + } + }, + { + request: { + path: '/api/v1/projects/testproject', + method: 'GET' + }, + response: { + data: { + "owner": "thuva4", + "_id": "5a0c022f9a07c846d3c2cc94", + "creation_date": "2017-11-15 14:30:31.200259", + "description": "dsfsd", + "name": "testproject" + } + } + }, + { + request: { + path: '/api/v1/projects/testproject/cases', + method: 'GET' + }, + response: { + data: { + "testcases": [ + { + "project_name": "testproject", + "run": null, + "description": null, + "tags": null, + "creation_date": "2017-12-20 18:47:04.025544", + "dependencies": null, + "tier": null, + "trust": null, + "blocking": null, + "name": "testCase", + "ci_loop": null, + "url": null, + "version": null, + "criteria": null, + "domains": null, + "_id": "5a3a62d09a07c836e06858fb", + "catalog_description": null + } + ] + } + } + }, + { + request: { + path: '/api/v1/projects/testproject/cases/testCase', + method: 'GET' + }, + response: { + data: { + "project_name": "testproject", + "run": null, + "description": null, + "tags": null, + "creation_date": "2017-12-20 18:47:04.025544", + "dependencies": null, + "tier": null, + "trust": null, + "blocking": null, + "name": "testCase", + "ci_loop": null, + "url": null, + "version": null, + "criteria": null, + "domains": null, + "_id": "5a3a62d09a07c836e06858fb", + "catalog_description": null + } + } + } + ]); + }); + + afterEach(function(){ + mock.teardown(); + }); + + it( 'should show the testCases for user', function() { + browser.get(baseURL+"#/projects/testproject"); + var testCases = element(by.linkText('Test Cases')); + testCases.click(); + var row = element.all(by.repeater('(index, testcase) in testCasesCtrl.data.testcases')).first(); + var cells = row.all(by.tagName('td')); + expect(cells.get(1).getText()).toContain("testCase"); + }); + + it( 'navigate user to testCase page', function() { + browser.get(baseURL+"#/projects/testproject"); + var testCases = element(by.linkText('Test Cases')); + testCases.click(); + var testCase = element(by.linkText('testCase')); + testCase.click(); + var EC = browser.ExpectedConditions; + browser.wait(EC.urlContains(baseURL+ '#/projects/testproject/testCase'), 10000); + }); + + it('create button is visible for user ', function () { + browser.get(baseURL+"#/projects/testproject"); + var testCases = element(by.linkText('Test Cases')); + testCases.click(); + var buttonCreate = element(by.buttonText('Create')); + expect(buttonCreate.isDisplayed()).toBe(true); + }); + + it('Delete button is visible for user ', function () { + browser.get(baseURL+"#/projects/testproject"); + var testCases = element(by.linkText('Test Cases')); + testCases.click(); + var buttonDelete = element(by.buttonText('Delete')); + expect(buttonDelete.isDisplayed()).toBe(true); + }); + + it('delete Operation is visible for user ', function () { + browser.get(baseURL+"#/projects/testproject"); + var testCases = element(by.linkText('Test Cases')); + testCases.click(); + var deleteOperation = element(by.css('a[title=Delete]')); + expect(deleteOperation.isDisplayed()).toBe(true); + }); + + it('Edit Operation is visible for user ', function () { + browser.get(baseURL+"#/projects/testproject"); + var testCases = element(by.linkText('Test Cases')); + testCases.click(); + var editOperation = element(by.css('a[title=Edit]')); + expect(editOperation.isDisplayed()).toBe(true); + }); + + it('Create the test case', function () { + browser.get(baseURL+"#/projects/testproject"); + var testCases = element(by.linkText('Test Cases')); + testCases.click(); + var buttonCreate = element(by.buttonText('Create')); + buttonCreate.click(); + var name = element(by.model('TestCaseModalCtrl.testcase.name')); + var EC = browser.ExpectedConditions; + browser.wait(EC.visibilityOf(name), 5000); + name.sendKeys('test'); + var buttonOK = element(by.buttonText('Ok')); + buttonOK.click(); + expect(element(by.cssContainingText(".alert","Testcase is successfully created.")) + .isDisplayed()).toBe(true); + }); + + it('Showing error when creating with a empty name ', function () { + browser.get(baseURL+"#/projects/testproject"); + var testCases = element(by.linkText('Test Cases')); + testCases.click(); + var buttonCreate = element(by.buttonText('Create')); + buttonCreate.click(); + var name = element(by.model('TestCaseModalCtrl.testcase.name')); + var EC = browser.ExpectedConditions; + browser.wait(EC.visibilityOf(name), 5000); + var buttonOK = element(by.buttonText('Ok')); + buttonOK.click(); + expect(element(by.cssContainingText(".alert","Name is missing.")) + .isDisplayed()).toBe(true); + }); + + it('cancel the delete confimation modal of the test case ', function () { + browser.get(baseURL+"#/projects/testproject"); + var testCases = element(by.linkText('Test Cases')); + testCases.click(); + var deleteOperation = element(by.css('a[title=Delete]')); + deleteOperation.click(); + var buttonCancel = element(by.buttonText('Cancel')); + buttonCancel.click(); + expect(buttonCancel.isPresent()).toBe(false); + }); + + it('Delete the test case ', function () { + browser.get(baseURL+"#/projects/testproject"); + var testCases = element(by.linkText('Test Cases')); + testCases.click(); + var deleteOperation = element(by.css('a[title=Delete]')); + deleteOperation.click(); + var buttonOK = element(by.buttonText('Ok')); + buttonOK.click(); + expect(element(by.cssContainingText(".alert","Test case is successfully deleted")) + .isDisplayed()).toBe(true); + }); + + it('cancel the Edit modal of the test case ', function () { + browser.get(baseURL+"#/projects/testproject"); + var testCases = element(by.linkText('Test Cases')); + testCases.click(); + var editOperation = element(by.css('a[title=Edit]')); + editOperation.click(); + var name = element(by.model('TestCaseModalCtrl.testcase.name')); + var EC = browser.ExpectedConditions; + browser.wait(EC.visibilityOf(name), 5000); + name.sendKeys('test1'); + var buttonCancel = element(by.buttonText('Cancel')); + buttonCancel.click(); + expect(name.isPresent()).toBe(false); + }); + + it('Edit the test case ', function () { + browser.get(baseURL+"#/projects/testproject"); + var testCases = element(by.linkText('Test Cases')); + testCases.click(); + var editOperation = element(by.css('a[title=Edit]')); + editOperation.click(); + var name = element(by.model('TestCaseModalCtrl.testcase.name')); + var EC = browser.ExpectedConditions; + browser.wait(EC.visibilityOf(name), 5000); + name.sendKeys('test1'); + var buttonOK = element(by.buttonText('Ok')); + buttonOK.click(); + expect(element(by.cssContainingText(".alert","Test case is successfully updated")) + .isDisplayed()).toBe(true); + }); + + it('view the test case ', function () { + browser.get(baseURL+"#/projects/testproject"); + var testCases = element(by.linkText('Test Cases')); + testCases.click(); + var viewOperation = element(by.linkText('testCase')); + viewOperation.click(); + var name = element(by.model('TestCaseModalCtrl.testcase.name')); + var EC = browser.ExpectedConditions; + browser.wait(EC.urlContains(baseURL+ '#/projects/testproject/testCase'), 10000); + }); + + it('Batch Delete the test Cases ', function () { + browser.get(baseURL+"#/projects/testproject"); + var testCases = element(by.linkText('Test Cases')); + testCases.click(); + var checkBox = element(by.model('testCasesCtrl.checkBox[index]')); + checkBox.click(); + var buttonDelete = element(by.buttonText('Delete'));; + buttonDelete.click(); + var buttonOK = element(by.buttonText('Ok')); + buttonOK.click(); + expect(element(by.cssContainingText(".alert","Test case is successfully deleted")) + .isDisplayed()).toBe(true); + }); +}) diff --git a/testapi/opnfv_testapi/tests/unit/fake_pymongo.py b/testapi/opnfv_testapi/tests/unit/fake_pymongo.py index 39b7e6a..041e6e8 100644 --- a/testapi/opnfv_testapi/tests/unit/fake_pymongo.py +++ b/testapi/opnfv_testapi/tests/unit/fake_pymongo.py @@ -178,6 +178,9 @@ class MemDb(object): elif i_k == 'versions.projects.project': return self._in_scenarios_project(i_v, content) + elif isinstance(v, re._pattern_type): + if v.match(content.get(k, None)) is None: + return False elif content.get(k, None) != v: return False @@ -285,6 +288,7 @@ pods = MemDb('pods') projects = MemDb('projects') testcases = MemDb('testcases') results = MemDb('results') +deployresults = MemDb('deployresults') scenarios = MemDb('scenarios') tokens = MemDb('tokens') users = MemDb('users') diff --git a/testapi/opnfv_testapi/tests/unit/handlers/test_base.py b/testapi/opnfv_testapi/tests/unit/handlers/test_base.py index 4e5c0d9..6436b8b 100644 --- a/testapi/opnfv_testapi/tests/unit/handlers/test_base.py +++ b/testapi/opnfv_testapi/tests/unit/handlers/test_base.py @@ -36,14 +36,14 @@ class TestBase(testing.AsyncHTTPTestCase): role='community-ci', _id=str(ObjectId()), owner='ValidUser', - create_date=str(datetime.now())) + creation_date=str(datetime.now())) self.pod_e = pod_models.Pod(name='zte-pod2', mode='metal', details='zte pod 2', role='production-ci', _id=str(ObjectId()), owner='ValidUser', - create_date=str(datetime.now())) + creation_date=str(datetime.now())) self.project_e = project_models.Project( name='functest', description='functest test', @@ -81,6 +81,16 @@ class TestBase(testing.AsyncHTTPTestCase): self.config_patcher.start() self.db_patcher.start() + @staticmethod + def load_json(json_file): + abs_file = path.join(path.dirname(__file__), + '../templates', + json_file + '.json') + with open(abs_file, 'r') as f: + loader = json.load(f) + f.close() + return loader + def get_app(self): from opnfv_testapi.cmd import server return server.make_app() @@ -210,4 +220,5 @@ class TestBase(testing.AsyncHTTPTestCase): fake_pymongo.projects.clear() fake_pymongo.testcases.clear() fake_pymongo.results.clear() + fake_pymongo.deployresults.clear() fake_pymongo.scenarios.clear() diff --git a/testapi/opnfv_testapi/tests/unit/handlers/test_deploy_result.py b/testapi/opnfv_testapi/tests/unit/handlers/test_deploy_result.py new file mode 100644 index 0000000..65e765e --- /dev/null +++ b/testapi/opnfv_testapi/tests/unit/handlers/test_deploy_result.py @@ -0,0 +1,201 @@ +############################################################################## +# Copyright (c) 2016 ZTE Corporation +# feng.xiaowei@zte.com.cn +# 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 copy +from datetime import datetime +from datetime import timedelta +import httplib +import urllib + +from opnfv_testapi.common import message +from opnfv_testapi.models import deploy_result_models as drm +from opnfv_testapi.tests.unit import executor +from opnfv_testapi.tests.unit import fake_pymongo +from opnfv_testapi.tests.unit.handlers import test_base as base + + +class DeployResultBase(base.TestBase): + @executor.mock_valid_lfid() + def setUp(self): + super(DeployResultBase, self).setUp() + self.req_d = drm.DeployResultCreateRequest.from_dict( + self.load_json('deploy_result')) + self.req_d.start_date = str(datetime.now()) + self.req_d.stop_date = str(datetime.now() + timedelta(minutes=1)) + self.get_res = drm.DeployResult + self.list_res = drm.DeployResults + self.basePath = '/api/v1/deployresults' + fake_pymongo.pods.insert(self.pod_d.format()) + + def assert_res(self, deploy_result, req=None): + if req is None: + req = self.req_d + print req.format() + self.assertEqual(deploy_result, req) + self.assertIsNotNone(deploy_result._id) + + def _create_d(self): + _, res = self.create_d() + return res.href.split('/')[-1] + + +class DeployResultCreate(DeployResultBase): + @executor.create(httplib.BAD_REQUEST, message.no_body()) + def test_nobody(self): + return None + + @executor.create(httplib.BAD_REQUEST, message.missing('pod_name')) + def test_podNotProvided(self): + req = self.req_d + req.pod_name = None + return req + + @executor.create(httplib.BAD_REQUEST, message.missing('installer')) + def test_installerNotProvided(self): + req = self.req_d + req.installer = None + return req + + @executor.create(httplib.BAD_REQUEST, message.missing('scenario')) + def test_testcaseNotProvided(self): + req = self.req_d + req.scenario = None + return req + + @executor.create(httplib.BAD_REQUEST, + message.invalid_value('criteria', ['PASS', 'FAIL'])) + def test_invalid_criteria(self): + req = self.req_d + req.criteria = 'invalid' + return req + + @executor.create(httplib.FORBIDDEN, message.not_found_base) + def test_noPod(self): + req = self.req_d + req.pod_name = 'notExistPod' + return req + + @executor.create(httplib.OK, 'assert_href') + def test_success(self): + return self.req_d + + +class DeployResultGet(DeployResultBase): + def setUp(self): + super(DeployResultGet, self).setUp() + self.req_10d_before = self._create_changed_date(days=-10) + self.req_d_id = self._create_d() + self.req_10d_later = self._create_changed_date(days=10) + + @executor.query(httplib.OK, '_query_success', 3) + def test_queryInstaller(self): + return self._set_query('installer') + + @executor.query(httplib.OK, '_query_success', 3) + def test_queryVersion(self): + return self._set_query('version') + + @executor.query(httplib.OK, '_query_success', 3) + def test_queryPod(self): + return self._set_query('pod_name') + + @executor.query(httplib.OK, '_query_success', 3) + def test_queryJob(self): + return self._set_query('job_name') + + @executor.query(httplib.OK, '_query_success', 1) + def test_queryBuildId(self): + return self._set_query('build_id') + + @executor.query(httplib.OK, '_query_success', 3) + def test_queryScenario(self): + return self._set_query('scenario') + + @executor.query(httplib.OK, '_query_success', 3) + def test_queryUpstreamJobName(self): + return self._set_query('upstream_job_name') + + @executor.query(httplib.OK, '_query_success', 1) + def test_queryUpstreamBuildId(self): + return self._set_query('upstream_build_id') + + @executor.query(httplib.OK, '_query_success', 3) + def test_queryCriteria(self): + return self._set_query('criteria') + + @executor.query(httplib.BAD_REQUEST, message.must_int('period')) + def test_queryPeriodNotInt(self): + return self._set_query(period='a') + + @executor.query(httplib.OK, '_query_period_one', 1) + def test_queryPeriodSuccess(self): + return self._set_query(period=5) + + @executor.query(httplib.BAD_REQUEST, message.must_int('last')) + def test_queryLastNotInt(self): + return self._set_query(last='a') + + @executor.query(httplib.OK, '_query_last_one', 1) + def test_queryLast(self): + return self._set_query(last=1) + + @executor.query(httplib.OK, '_query_period_one', 1) + def test_combination(self): + return self._set_query('installer', + 'version', + 'pod_name', + 'job_name', + 'build_id', + 'scenario', + 'upstream_job_name', + 'upstream_build_id', + 'criteria', + period=5) + + @executor.query(httplib.OK, '_query_success', 1) + def test_filterErrorStartdate(self): + self._create_error_start_date(None) + self._create_error_start_date('None') + self._create_error_start_date('null') + self._create_error_start_date('') + return self._set_query(period=5) + + def _query_success(self, body, number): + self.assertEqual(number, len(body.deployresults)) + + def _query_last_one(self, body, number): + self.assertEqual(number, len(body.deployresults)) + self.assert_res(body.deployresults[0], self.req_10d_later) + + def _query_period_one(self, body, number): + self.assertEqual(number, len(body.deployresults)) + self.assert_res(body.deployresults[0], self.req_d) + + def _create_error_start_date(self, start_date): + req = copy.deepcopy(self.req_d) + req.start_date = start_date + self.create(req) + return req + + def _create_changed_date(self, **kwargs): + req = copy.deepcopy(self.req_d) + req.build_id = req.build_id + kwargs.get('days') + req.upstream_build_id = req.upstream_build_id + kwargs.get('days') + req.start_date = datetime.now() + timedelta(**kwargs) + req.stop_date = str(req.start_date + timedelta(minutes=10)) + req.start_date = str(req.start_date) + self.create(req) + return req + + def _set_query(self, *args, **kwargs): + query = [] + for arg in args: + query.append((arg, getattr(self.req_d, arg))) + for k, v in kwargs.iteritems(): + query.append((k, v)) + return urllib.urlencode(query) diff --git a/testapi/opnfv_testapi/tests/unit/handlers/test_pod.py b/testapi/opnfv_testapi/tests/unit/handlers/test_pod.py index 95ed8ba..2818513 100644 --- a/testapi/opnfv_testapi/tests/unit/handlers/test_pod.py +++ b/testapi/opnfv_testapi/tests/unit/handlers/test_pod.py @@ -7,10 +7,9 @@ # http://www.apache.org/licenses/LICENSE-2.0 ############################################################################## import httplib -import unittest from opnfv_testapi.common import message -from opnfv_testapi.models import pod_models +from opnfv_testapi.models import pod_models as pm from opnfv_testapi.tests.unit import executor from opnfv_testapi.tests.unit import fake_pymongo from opnfv_testapi.tests.unit.handlers import test_base as base @@ -19,26 +18,16 @@ from opnfv_testapi.tests.unit.handlers import test_base as base class TestPodBase(base.TestBase): def setUp(self): super(TestPodBase, self).setUp() - self.get_res = pod_models.Pod - self.list_res = pod_models.Pods + self.get_res = pm.Pod + self.list_res = pm.Pods self.basePath = '/api/v1/pods' - self.req_d = pod_models.PodCreateRequest(name=self.pod_d.name, - mode=self.pod_d.mode, - details=self.pod_d.details, - role=self.pod_d.role) - self.req_e = pod_models.PodCreateRequest(name=self.pod_e.name, - mode=self.pod_e.mode, - details=self.pod_e.details, - role=self.pod_e.role) + self.req_d = pm.PodCreateRequest.from_dict(self.pod_d.format()) + self.req_e = pm.PodCreateRequest.from_dict(self.pod_e.format()) def assert_get_body(self, pod, req=None): if not req: req = self.req_d - self.assertEqual(pod.owner, 'ValidUser') - self.assertEqual(pod.name, req.name) - self.assertEqual(pod.mode, req.mode) - self.assertEqual(pod.details, req.details) - self.assertEqual(pod.role, req.role) + self.assertEqual(pod, pm.Pod(owner='ValidUser', **req.format())) self.assertIsNotNone(pod.creation_date) self.assertIsNotNone(pod._id) @@ -61,12 +50,12 @@ class TestPodCreate(TestPodBase): @executor.mock_valid_lfid() @executor.create(httplib.BAD_REQUEST, message.missing('name')) def test_emptyName(self): - return pod_models.PodCreateRequest('') + return pm.PodCreateRequest('') @executor.mock_valid_lfid() @executor.create(httplib.BAD_REQUEST, message.missing('name')) def test_noneName(self): - return pod_models.PodCreateRequest(None) + return pm.PodCreateRequest(None) @executor.mock_valid_lfid() @executor.create(httplib.OK, 'assert_create_body') @@ -99,7 +88,7 @@ class TestPodGet(TestPodBase): @executor.get(httplib.OK, 'assert_get_body') def test_getOne(self): - return self.pod_d.name + return self.req_d.name @executor.get(httplib.OK, '_assert_list') def test_list(self): @@ -108,11 +97,7 @@ class TestPodGet(TestPodBase): def _assert_list(self, body): self.assertEqual(len(body.pods), 2) for pod in body.pods: - if self.pod_d.name == pod.name: + if self.req_d.name == pod.name: self.assert_get_body(pod) else: - self.assert_get_body(pod, self.pod_e) - - -if __name__ == '__main__': - unittest.main() + self.assert_get_body(pod, self.req_e) diff --git a/testapi/opnfv_testapi/tests/unit/handlers/test_result.py b/testapi/opnfv_testapi/tests/unit/handlers/test_result.py index bd482a6..f1f055e 100644 --- a/testapi/opnfv_testapi/tests/unit/handlers/test_result.py +++ b/testapi/opnfv_testapi/tests/unit/handlers/test_result.py @@ -12,115 +12,35 @@ from datetime import timedelta import httplib import json import urllib -import unittest from opnfv_testapi.common import message -from opnfv_testapi.models import result_models -from opnfv_testapi.models import testcase_models +from opnfv_testapi.models import result_models as rm from opnfv_testapi.tests.unit import executor from opnfv_testapi.tests.unit import fake_pymongo from opnfv_testapi.tests.unit.handlers import test_base as base -class Details(object): - def __init__(self, timestart=None, duration=None, status=None): - self.timestart = timestart - self.duration = duration - self.status = status - self.items = [{'item1': 1}, {'item2': 2}] - - def format(self): - return { - "timestart": self.timestart, - "duration": self.duration, - "status": self.status, - 'items': [{'item1': 1}, {'item2': 2}] - } - - @staticmethod - def from_dict(a_dict): - - if a_dict is None: - return None - - t = Details() - t.timestart = a_dict.get('timestart') - t.duration = a_dict.get('duration') - t.status = a_dict.get('status') - t.items = a_dict.get('items') - return t - - class TestResultBase(base.TestBase): + @executor.mock_valid_lfid() def setUp(self): super(TestResultBase, self).setUp() - self.pod = self.pod_d.name - self.project = 'functest' - self.case = 'vPing' - self.installer = 'fuel' - self.version = 'C' - self.build_tag = 'v3.0' - self.scenario = 'odl-l2' - self.criteria = 'PASS' - self.trust_indicator = result_models.TI(0.7) - self.start_date = str(datetime.now()) - self.stop_date = str(datetime.now() + timedelta(minutes=1)) - self.update_date = str(datetime.now() + timedelta(days=1)) - self.update_step = -0.05 - self.details = Details(timestart='0', duration='9s', status='OK') - 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.req_d = rm.ResultCreateRequest.from_dict( + self.load_json('test_result')) + self.req_d.start_date = str(datetime.now()) + self.req_d.stop_date = str(datetime.now() + timedelta(minutes=1)) + self.get_res = rm.TestResult + self.list_res = rm.TestResults + self.update_res = rm.TestResult self.basePath = '/api/v1/results' - fake_pymongo.projects.insert(self.project_e.format()) - self.req_testcase = testcase_models.TestcaseCreateRequest( - self.case, - '/cases/vping', - 'vping-ssh test') - fake_pymongo.pods.insert(self.pod_d.format()) - self.create_help('/api/v1/projects/%s/cases', - self.req_testcase, - self.project) + fake_pymongo.pods.insert({'name': self.req_d.pod_name}) + fake_pymongo.projects.insert({'name': self.req_d.project_name}) + fake_pymongo.testcases.insert({'name': self.req_d.case_name, + 'project_name': self.req_d.project_name}) def assert_res(self, result, req=None): if req is None: req = self.req_d - self.assertEqual(result.pod_name, req.pod_name) - self.assertEqual(result.project_name, req.project_name) - self.assertEqual(result.case_name, req.case_name) - self.assertEqual(result.installer, req.installer) - self.assertEqual(result.version, req.version) - details_req = Details.from_dict(req.details) - details_res = Details.from_dict(result.details) - self.assertEqual(details_res.duration, details_req.duration) - self.assertEqual(details_res.timestart, details_req.timestart) - self.assertEqual(details_res.status, details_req.status) - self.assertEqual(details_res.items, details_req.items) - self.assertEqual(result.build_tag, req.build_tag) - self.assertEqual(result.scenario, req.scenario) - self.assertEqual(result.criteria, req.criteria) - self.assertEqual(result.start_date, req.start_date) - self.assertEqual(result.stop_date, req.stop_date) - self.assertIsNotNone(result._id) - ti = result.trust_indicator - self.assertEqual(ti.current, req.trust_indicator.current) - if ti.histories: - history = ti.histories[0] - self.assertEqual(history.date, self.update_date) - self.assertEqual(history.step, self.update_step) + self.assertEqual(result, req) def _create_d(self): _, res = self.create_d() @@ -203,17 +123,8 @@ class TestResultCreate(TestResultBase): @executor.create(httplib.OK, '_assert_no_ti') def test_no_ti(self): - 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) + req = copy.deepcopy(self.req_d) + req.trust_indicator = rm.TI(0) self.actual_req = req return req @@ -369,8 +280,13 @@ class TestResultGet(TestResultBase): def _set_query(self, *args, **kwargs): def get_value(arg): - return self.__getattribute__(arg) \ - if arg != 'trust_indicator' else self.trust_indicator.current + if arg in ['pod', 'project', 'case']: + return getattr(self.req_d, arg + '_name') + elif arg == 'trust_indicator': + return self.req_d.trust_indicator.current + else: + return getattr(self.req_d, arg) + query = [] for arg in args: query.append((arg, get_value(arg))) @@ -386,24 +302,15 @@ class TestResultUpdate(TestResultBase): @executor.update(httplib.OK, '_assert_update_ti') def test_success(self): - new_ti = copy.deepcopy(self.trust_indicator) - new_ti.current += 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 = result_models.ResultUpdateRequest(trust_indicator=new_ti) - self.update_req = new_data + update_date = str(datetime.now() + timedelta(days=1)) + update_step = -0.05 + self.after_update = copy.deepcopy(self.req_d) + self.after_update.trust_indicator.current += update_step + self.after_update.trust_indicator.histories.append( + rm.TIHistory(update_date, update_step)) + update = rm.ResultUpdateRequest( + trust_indicator=self.after_update.trust_indicator) return update, self.req_d_id def _assert_update_ti(self, request, body): - ti = body.trust_indicator - self.assertEqual(ti.current, request.trust_indicator.current) - if ti.histories: - history = ti.histories[0] - self.assertEqual(history.date, self.update_date) - self.assertEqual(history.step, self.update_step) - - -if __name__ == '__main__': - unittest.main() + self.assert_res(body, self.after_update) diff --git a/testapi/opnfv_testapi/tests/unit/handlers/test_scenario.py b/testapi/opnfv_testapi/tests/unit/handlers/test_scenario.py index de7777a..481078d 100644 --- a/testapi/opnfv_testapi/tests/unit/handlers/test_scenario.py +++ b/testapi/opnfv_testapi/tests/unit/handlers/test_scenario.py @@ -1,12 +1,10 @@ +from datetime import datetime import functools import httplib -import json -import os - -from datetime import datetime from opnfv_testapi.common import message -import opnfv_testapi.models.scenario_models as models +import opnfv_testapi.models.scenario_models as sm +from opnfv_testapi.tests.unit import executor from opnfv_testapi.tests.unit.handlers import test_base as base @@ -17,26 +15,13 @@ def _none_default(check, default): class TestScenarioBase(base.TestBase): def setUp(self): super(TestScenarioBase, self).setUp() - self.get_res = models.Scenario - self.list_res = models.Scenarios + self.get_res = sm.Scenario + self.list_res = sm.Scenarios self.basePath = '/api/v1/scenarios' - self.req_d = self._load_request('scenario-c1.json') - self.req_2 = self._load_request('scenario-c2.json') - - def tearDown(self): - pass - - def assert_body(self, project, req=None): - pass - - @staticmethod - def _load_request(f_req): - abs_file = os.path.join(os.path.dirname(__file__), f_req) - with open(abs_file, 'r') as f: - loader = json.load(f) - f.close() - return loader + self.req_d = self.load_json('scenario-c1') + self.req_2 = self.load_json('scenario-c2') + @executor.mock_valid_lfid() def create_return_name(self, req): _, res = self.create(req) return res.href.split('/')[-1] @@ -47,7 +32,7 @@ class TestScenarioBase(base.TestBase): req = self.req_d self.assertIsNotNone(scenario._id) self.assertIsNotNone(scenario.creation_date) - self.assertEqual(scenario, models.Scenario.from_dict(req)) + self.assertEqual(scenario, sm.Scenario.from_dict(req)) @staticmethod def set_query(*args): @@ -62,27 +47,32 @@ class TestScenarioBase(base.TestBase): class TestScenarioCreate(TestScenarioBase): + @executor.mock_valid_lfid() def test_withoutBody(self): (code, body) = self.create() self.assertEqual(code, httplib.BAD_REQUEST) + @executor.mock_valid_lfid() def test_emptyName(self): - req_empty = models.ScenarioCreateRequest('') + req_empty = sm.ScenarioCreateRequest('') (code, body) = self.create(req_empty) self.assertEqual(code, httplib.BAD_REQUEST) self.assertIn(message.missing('name'), body) + @executor.mock_valid_lfid() def test_noneName(self): - req_none = models.ScenarioCreateRequest(None) + req_none = sm.ScenarioCreateRequest(None) (code, body) = self.create(req_none) self.assertEqual(code, httplib.BAD_REQUEST) self.assertIn(message.missing('name'), body) + @executor.mock_valid_lfid() def test_success(self): (code, body) = self.create_d() self.assertEqual(code, httplib.OK) self.assert_create_body(body) + @executor.mock_valid_lfid() def test_alreadyExist(self): self.create_d() (code, body) = self.create_d() @@ -145,6 +135,7 @@ class TestScenarioDelete(TestScenarioBase): code, body = self.delete('notFound') self.assertEqual(code, httplib.NOT_FOUND) + @executor.mock_valid_lfid() def test_success(self): scenario = self.create_return_name(self.req_d) code, _ = self.delete(scenario) @@ -199,9 +190,10 @@ class TestScenarioUpdate(TestScenarioBase): return wrapper return _update_partial + @executor.mock_valid_lfid() @update_partial('_add', '_success') def test_addScore(self): - add = models.ScenarioScore(date=str(datetime.now()), score='11/12') + add = sm.ScenarioScore(date=str(datetime.now()), score='11/12') projects = self.req_d['installers'][0]['versions'][0]['projects'] functest = filter(lambda f: f['project'] == 'functest', projects)[0] functest['scores'].append(add.format()) @@ -210,9 +202,10 @@ class TestScenarioUpdate(TestScenarioBase): return add + @executor.mock_valid_lfid() @update_partial('_add', '_success') def test_addTrustIndicator(self): - add = models.ScenarioTI(date=str(datetime.now()), status='gold') + add = sm.ScenarioTI(date=str(datetime.now()), status='gold') projects = self.req_d['installers'][0]['versions'][0]['projects'] functest = filter(lambda f: f['project'] == 'functest', projects)[0] functest['trust_indicators'].append(add.format()) @@ -221,6 +214,7 @@ class TestScenarioUpdate(TestScenarioBase): return add + @executor.mock_valid_lfid() @update_partial('_add', '_success') def test_addCustoms(self): adds = ['odl', 'parser', 'vping_ssh'] @@ -231,6 +225,7 @@ class TestScenarioUpdate(TestScenarioBase): self.locate_project) return adds + @executor.mock_valid_lfid() @update_partial('_update', '_success') def test_updateCustoms(self): updates = ['odl', 'parser', 'vping_ssh'] @@ -242,6 +237,7 @@ class TestScenarioUpdate(TestScenarioBase): return updates + @executor.mock_valid_lfid() @update_partial('_delete', '_success') def test_deleteCustoms(self): deletes = ['vping_ssh'] @@ -253,46 +249,53 @@ class TestScenarioUpdate(TestScenarioBase): return deletes + @executor.mock_valid_lfid() @update_url_fixture('projects') @update_partial('_add', '_success') def test_addProjects_succ(self): - add = models.ScenarioProject(project='qtip').format() + add = sm.ScenarioProject(project='qtip').format() self.req_d['installers'][0]['versions'][0]['projects'].append(add) return [add] + @executor.mock_valid_lfid() @update_url_fixture('projects') @update_partial('_add', '_conflict') def test_addProjects_already_exist(self): - add = models.ScenarioProject(project='functest').format() + add = sm.ScenarioProject(project='functest').format() return [add] + @executor.mock_valid_lfid() @update_url_fixture('projects') @update_partial('_add', '_bad_request') def test_addProjects_bad_schema(self): - add = models.ScenarioProject(project='functest').format() + add = sm.ScenarioProject(project='functest').format() add['score'] = None return [add] + @executor.mock_valid_lfid() @update_url_fixture('projects') @update_partial('_update', '_success') def test_updateProjects_succ(self): - update = models.ScenarioProject(project='qtip').format() + update = sm.ScenarioProject(project='qtip').format() self.req_d['installers'][0]['versions'][0]['projects'] = [update] return [update] + @executor.mock_valid_lfid() @update_url_fixture('projects') @update_partial('_update', '_conflict') def test_updateProjects_duplicated(self): - update = models.ScenarioProject(project='qtip').format() + update = sm.ScenarioProject(project='qtip').format() return [update, update] + @executor.mock_valid_lfid() @update_url_fixture('projects') @update_partial('_update', '_bad_request') def test_updateProjects_bad_schema(self): - update = models.ScenarioProject(project='functest').format() + update = sm.ScenarioProject(project='functest').format() update['score'] = None return [update] + @executor.mock_valid_lfid() @update_url_fixture('projects') @update_partial('_delete', '_success') def test_deleteProjects(self): @@ -303,54 +306,62 @@ class TestScenarioUpdate(TestScenarioBase): projects) return deletes + @executor.mock_valid_lfid() @update_url_fixture('owner') @update_partial('_update', '_success') def test_changeOwner(self): new_owner = 'new_owner' - update = models.ScenarioChangeOwnerRequest(new_owner).format() + update = sm.ScenarioChangeOwnerRequest(new_owner).format() self.req_d['installers'][0]['versions'][0]['owner'] = new_owner return update + @executor.mock_valid_lfid() @update_url_fixture('versions') @update_partial('_add', '_success') def test_addVersions_succ(self): - add = models.ScenarioVersion(version='Euphrates').format() + add = sm.ScenarioVersion(version='Euphrates').format() self.req_d['installers'][0]['versions'].append(add) return [add] + @executor.mock_valid_lfid() @update_url_fixture('versions') @update_partial('_add', '_conflict') def test_addVersions_already_exist(self): - add = models.ScenarioVersion(version='master').format() + add = sm.ScenarioVersion(version='master').format() return [add] + @executor.mock_valid_lfid() @update_url_fixture('versions') @update_partial('_add', '_bad_request') def test_addVersions_bad_schema(self): - add = models.ScenarioVersion(version='euphrates').format() + add = sm.ScenarioVersion(version='euphrates').format() add['notexist'] = None return [add] + @executor.mock_valid_lfid() @update_url_fixture('versions') @update_partial('_update', '_success') def test_updateVersions_succ(self): - update = models.ScenarioVersion(version='euphrates').format() + update = sm.ScenarioVersion(version='euphrates').format() self.req_d['installers'][0]['versions'] = [update] return [update] + @executor.mock_valid_lfid() @update_url_fixture('versions') @update_partial('_update', '_conflict') def test_updateVersions_duplicated(self): - update = models.ScenarioVersion(version='euphrates').format() + update = sm.ScenarioVersion(version='euphrates').format() return [update, update] + @executor.mock_valid_lfid() @update_url_fixture('versions') @update_partial('_update', '_bad_request') def test_updateVersions_bad_schema(self): - update = models.ScenarioVersion(version='euphrates').format() + update = sm.ScenarioVersion(version='euphrates').format() update['not_owner'] = 'Iam' return [update] + @executor.mock_valid_lfid() @update_url_fixture('versions') @update_partial('_delete', '_success') def test_deleteVersions(self): @@ -361,46 +372,53 @@ class TestScenarioUpdate(TestScenarioBase): versions) return deletes + @executor.mock_valid_lfid() @update_url_fixture('installers') @update_partial('_add', '_success') def test_addInstallers_succ(self): - add = models.ScenarioInstaller(installer='daisy').format() + add = sm.ScenarioInstaller(installer='daisy').format() self.req_d['installers'].append(add) return [add] + @executor.mock_valid_lfid() @update_url_fixture('installers') @update_partial('_add', '_conflict') def test_addInstallers_already_exist(self): - add = models.ScenarioInstaller(installer='apex').format() + add = sm.ScenarioInstaller(installer='apex').format() return [add] + @executor.mock_valid_lfid() @update_url_fixture('installers') @update_partial('_add', '_bad_request') def test_addInstallers_bad_schema(self): - add = models.ScenarioInstaller(installer='daisy').format() + add = sm.ScenarioInstaller(installer='daisy').format() add['not_exist'] = 'not_exist' return [add] + @executor.mock_valid_lfid() @update_url_fixture('installers') @update_partial('_update', '_success') def test_updateInstallers_succ(self): - update = models.ScenarioInstaller(installer='daisy').format() + update = sm.ScenarioInstaller(installer='daisy').format() self.req_d['installers'] = [update] return [update] + @executor.mock_valid_lfid() @update_url_fixture('installers') @update_partial('_update', '_conflict') def test_updateInstallers_duplicated(self): - update = models.ScenarioInstaller(installer='daisy').format() + update = sm.ScenarioInstaller(installer='daisy').format() return [update, update] + @executor.mock_valid_lfid() @update_url_fixture('installers') @update_partial('_update', '_bad_request') def test_updateInstallers_bad_schema(self): - update = models.ScenarioInstaller(installer='daisy').format() + update = sm.ScenarioInstaller(installer='daisy').format() update['not_exist'] = 'not_exist' return [update] + @executor.mock_valid_lfid() @update_url_fixture('installers') @update_partial('_delete', '_success') def test_deleteInstallers(self): @@ -411,19 +429,21 @@ class TestScenarioUpdate(TestScenarioBase): installers) return deletes + @executor.mock_valid_lfid() @update_url_fixture('rename') @update_partial('_update', '_success') def test_renameScenario(self): new_name = 'new_scenario_name' - update = models.ScenarioUpdateRequest(name=new_name) + update = sm.ScenarioUpdateRequest(name=new_name) self.req_d['name'] = new_name return update + @executor.mock_valid_lfid() @update_url_fixture('rename') @update_partial('_update', '_forbidden') def test_renameScenario_exist(self): new_name = self.req_d['name'] - update = models.ScenarioUpdateRequest(name=new_name) + update = sm.ScenarioUpdateRequest(name=new_name) return update def _add(self, update_req): diff --git a/testapi/opnfv_testapi/tests/unit/handlers/test_testcase.py b/testapi/opnfv_testapi/tests/unit/handlers/test_testcase.py index d5e32e3..9a2bf58 100644 --- a/testapi/opnfv_testapi/tests/unit/handlers/test_testcase.py +++ b/testapi/opnfv_testapi/tests/unit/handlers/test_testcase.py @@ -6,12 +6,10 @@ # which accompanies this distribution, and is available at # http://www.apache.org/licenses/LICENSE-2.0 ############################################################################## -import copy import httplib -import unittest from opnfv_testapi.common import message -from opnfv_testapi.models import testcase_models +from opnfv_testapi.models import testcase_models as tcm from opnfv_testapi.tests.unit import executor from opnfv_testapi.tests.unit import fake_pymongo from opnfv_testapi.tests.unit.handlers import test_base as base @@ -21,57 +19,56 @@ class TestCaseBase(base.TestBase): def setUp(self): super(TestCaseBase, self).setUp() self.project = 'functest' - 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.req_d = tcm.TestcaseCreateRequest.from_dict( + self.load_json('testcase_d')) + self.req_e = tcm.TestcaseCreateRequest.from_dict( + self.load_json('testcase_e')) + self.update_req = tcm.TestcaseUpdateRequest(project_name=self.project, + **self.req_e.format()) + + self.get_res = tcm.Testcase + self.list_res = tcm.Testcases + self.update_res = tcm.Testcase self.basePath = '/api/v1/projects/%s/cases' fake_pymongo.projects.insert(self.project_e.format()) + print self.req_d.format() def assert_body(self, case, req=None): if not req: req = self.req_d - self.assertEqual(case.name, req.name) - self.assertEqual(case.description, req.description) - self.assertEqual(case.url, req.url) + self.assertEqual(req, + tcm.TestcaseCreateRequest.from_dict(case.format())) + self.assertEqual(case.project_name, self.project) self.assertIsNotNone(case._id) self.assertIsNotNone(case.creation_date) - def assert_update_body(self, old, new, req=None): + def assert_update_body(self, new_record, req=None): if not req: req = self.req_d - self.assertEqual(new.name, req.name) - self.assertEqual(new.description, req.description) - self.assertEqual(new.url, old.url) - self.assertIsNotNone(new._id) - self.assertIsNotNone(new.creation_date) + self.assertEqual(req, new_record) + self.assertIsNotNone(new_record._id) + self.assertIsNotNone(new_record.creation_date) + @executor.mock_valid_lfid() def create_d(self): return super(TestCaseBase, self).create_d(self.project) + @executor.mock_valid_lfid() def create_e(self): return super(TestCaseBase, self).create_e(self.project) def get(self, case=None): return super(TestCaseBase, self).get(self.project, case) + @executor.mock_valid_lfid() def create(self, req=None, *args): return super(TestCaseBase, self).create(req, self.project) + @executor.mock_valid_lfid() def update(self, new=None, case=None): return super(TestCaseBase, self).update(new, self.project, case) + @executor.mock_valid_lfid() def delete(self, case): return super(TestCaseBase, self).delete(self.project, case) @@ -88,12 +85,12 @@ class TestCaseCreate(TestCaseBase): @executor.create(httplib.BAD_REQUEST, message.missing('name')) def test_emptyName(self): - req_empty = testcase_models.TestcaseCreateRequest('') + req_empty = tcm.TestcaseCreateRequest('') return req_empty @executor.create(httplib.BAD_REQUEST, message.missing('name')) def test_noneName(self): - req_none = testcase_models.TestcaseCreateRequest(None) + req_none = tcm.TestcaseCreateRequest(None) return req_none @executor.create(httplib.OK, '_assert_success') @@ -146,31 +143,33 @@ class TestCaseUpdate(TestCaseBase): @executor.update(httplib.NOT_FOUND, message.not_found_base) def test_notFound(self): - return self.update_e, 'notFound' + update = tcm.TestcaseUpdateRequest(description='update description') + return update, 'notFound' @executor.update(httplib.FORBIDDEN, message.exist_base) def test_newNameExist(self): self.create_e() - return self.update_e, self.req_d.name + return self.update_req, self.req_d.name @executor.update(httplib.FORBIDDEN, message.no_update()) def test_noUpdate(self): - return self.update_d, self.req_d.name + update = tcm.TestcaseUpdateRequest(project_name=self.project, + **self.req_d.format()) + return update, self.req_d.name @executor.update(httplib.OK, '_update_success') def test_success(self): - return self.update_e, self.req_d.name + return self.update_req, self.req_d.name @executor.update(httplib.OK, '_update_success') def test_with_dollar(self): - update = copy.deepcopy(self.update_d) - update.description = {'2. change': 'dollar change'} - return update, self.req_d.name + self.update_req.description = {'2. change': 'dollar change'} + return self.update_req, self.req_d.name def _update_success(self, request, body): - self.assert_update_body(self.req_d, body, request) + self.assert_update_body(body, request) _, new_body = self.get(request.name) - self.assert_update_body(self.req_d, new_body, request) + self.assert_update_body(new_body, request) class TestCaseDelete(TestCaseBase): @@ -190,7 +189,3 @@ class TestCaseDelete(TestCaseBase): self.assertEqual(body, '') code, body = self.get(self.req_d.name) self.assertEqual(code, httplib.NOT_FOUND) - - -if __name__ == '__main__': - unittest.main() diff --git a/testapi/opnfv_testapi/tests/unit/templates/deploy_result.json b/testapi/opnfv_testapi/tests/unit/templates/deploy_result.json new file mode 100644 index 0000000..8d4941d --- /dev/null +++ b/testapi/opnfv_testapi/tests/unit/templates/deploy_result.json @@ -0,0 +1,14 @@ +{ + "build_id": 100, + "scenario": "os-nosdn-nofeature-ha", + "stop_date": "", + "start_date": "", + "upstream_job_name": "daisy-job-master", + "version": "master", + "pod_name": "zte-pod1", + "criteria": "PASS", + "installer": "daisy", + "upstream_build_id": 100, + "job_name": "daisy-deploy-job-master", + "details": "" +}
\ No newline at end of file diff --git a/testapi/opnfv_testapi/tests/unit/handlers/scenario-c1.json b/testapi/opnfv_testapi/tests/unit/templates/scenario-c1.json index 1878022..1878022 100644 --- a/testapi/opnfv_testapi/tests/unit/handlers/scenario-c1.json +++ b/testapi/opnfv_testapi/tests/unit/templates/scenario-c1.json diff --git a/testapi/opnfv_testapi/tests/unit/handlers/scenario-c2.json b/testapi/opnfv_testapi/tests/unit/templates/scenario-c2.json index 980051c..980051c 100644 --- a/testapi/opnfv_testapi/tests/unit/handlers/scenario-c2.json +++ b/testapi/opnfv_testapi/tests/unit/templates/scenario-c2.json diff --git a/testapi/opnfv_testapi/tests/unit/templates/test_result.json b/testapi/opnfv_testapi/tests/unit/templates/test_result.json new file mode 100644 index 0000000..b7cb910 --- /dev/null +++ b/testapi/opnfv_testapi/tests/unit/templates/test_result.json @@ -0,0 +1,27 @@ +{ + "project_name": "functest", + "scenario": "odl-l2", + "trust_indicator": { + "current": 0.7, + "histories": [] + }, + "case_name": "vPing", + "build_tag": "v3.0", + "public": "true", + "version": "C", + "details": { + "timestart": "0", + "duration": "9s", + "status": "OK", + "items": [ + {"item1": 1}, + {"item2": 2} + ] + }, + "criteria": "PASS", + "installer": "fuel", + "pod_name": "zte-pod1", + "start_date": "", + "stop_date": "", + "user": "" +}
\ No newline at end of file diff --git a/testapi/opnfv_testapi/tests/unit/templates/testcase_d.json b/testapi/opnfv_testapi/tests/unit/templates/testcase_d.json new file mode 100644 index 0000000..7c36cb8 --- /dev/null +++ b/testapi/opnfv_testapi/tests/unit/templates/testcase_d.json @@ -0,0 +1,16 @@ +{ + "run": "vping.sh", + "name": "vping_ssh", + "ci_loop": "daily", + "tags": "", + "url": "/cases/vping_ssh", + "blocking": "true", + "domains": "os", + "dependencies": "", + "version": "euphrates", + "criteria": "PASS/FAIL", + "tier": "smoke", + "trust": "Silver", + "catalog_description": "", + "description": "vping-ssh test" +}
\ No newline at end of file diff --git a/testapi/opnfv_testapi/tests/unit/templates/testcase_e.json b/testapi/opnfv_testapi/tests/unit/templates/testcase_e.json new file mode 100644 index 0000000..c031309 --- /dev/null +++ b/testapi/opnfv_testapi/tests/unit/templates/testcase_e.json @@ -0,0 +1,16 @@ +{ + "run": "parser.sh", + "name": "parser-basics", + "ci_loop": "daily", + "tags": "", + "url": "/cases/parser", + "blocking": "false", + "domains": "vnf", + "dependencies": "", + "version": "master", + "criteria": "PASS/FAIL", + "tier": "features", + "trust": "Silver", + "catalog_description": "", + "description": "parser test" +}
\ No newline at end of file diff --git a/testapi/opnfv_testapi/ui/Gruntfile.js b/testapi/opnfv_testapi/ui/Gruntfile.js index dd116a0..1be08b5 100644 --- a/testapi/opnfv_testapi/ui/Gruntfile.js +++ b/testapi/opnfv_testapi/ui/Gruntfile.js @@ -1,154 +1,162 @@ module.exports = function (grunt) { - require('load-grunt-tasks')(grunt); - require('grunt-protractor-coverage')(grunt); - grunt.loadNpmTasks('grunt-shell-spawn'); - grunt.loadNpmTasks('grunt-wait'); - grunt.loadNpmTasks('grunt-contrib-copy'); - grunt.loadNpmTasks('grunt-contrib-connect'); - grunt.initConfig({ - connect: { - server: { - options: { - port: 8000, - base: './', - middleware: function(connect, options, middlewares) { - middlewares.unshift(function(req, res, next) { - if (req.method.toUpperCase() == 'POST' || req.method.toUpperCase() == "PUT"){ - req.method='GET'; - } - return next(); - }); - return middlewares; - } - } - } - }, - copy: { - assets: { - expand: true, - cwd: '../../3rd_party/static/testapi-ui/assets', - src: '**', - dest: 'testapi-ui/assets', - }, - components: { - expand: true, - cwd: 'components', - src: '**', - dest: 'testapi-ui/components', - }, - shared: { - expand: true, - cwd: 'shared', - src: '**', - dest: 'testapi-ui/shared', - }, - filesPng: { - expand: true, - src: '*.png', - dest: 'testapi-ui/', - }, - filesIco: { - expand: true, - src: '*.ico', - dest: 'testapi-ui/', - }, - filesJs: { - expand: true, - src: 'app.js', - dest: 'testapi-ui/', - }, - filesJson: { - expand: true, - src: 'config.json', - dest: 'testapi-ui/', - } - }, - wait: { - default: { - options: { - delay: 3000 - } - } - }, - shell: { - updateSelenium: { - command: 'node_modules/protractor/bin/webdriver-manager update', - options: { - async: false - } - }, - startSelenium: { - command: 'node_modules/protractor/bin/webdriver-manager start', - options: { - async: true - } - }, - deleteFiles: { - command: 'rm -r testapi-ui', - options: { - async: false - } - }, - options: { - stdout: false, - stderr: false - } - }, - instrument: { - files: ['components/**/*.js'], - options: { - lazy: false, - basePath: "./testapi-ui/" - } - }, - karma: { - unit: { - configFile: 'karma.conf.js' - } - }, - protractor_coverage: { - options: { - keepAlive: true, - noColor: false, - coverageDir: '../tests/UI/coverage', - args: { - specs: ['../tests/UI/e2e/podsControllerSpec.js', - '../tests/UI/e2e/projectsControllerSpec.js', - '../tests/UI/e2e/projectControllerSpec.js'] - } - }, - local: { - options: { - configFile: '../tests/UI/protractor-conf.js' - } - } - }, - makeReport: { - src: '../tests/UI/coverage/*.json', - options: { - print: 'detail' - } - } - }); - grunt.registerTask('test', [ - 'karma:unit' - ]); - grunt.registerTask('e2e', [ - 'copy:assets', - 'copy:components', - 'copy:shared', - 'copy:filesPng', - 'copy:filesIco', - 'copy:filesJs', - 'copy:filesJson', - 'instrument', - 'connect', - 'shell:updateSelenium', - 'shell:startSelenium', - 'wait:default', - 'protractor_coverage', - 'makeReport', - 'shell:deleteFiles' - ]); + require('load-grunt-tasks')(grunt); + require('grunt-protractor-coverage')(grunt); + grunt.loadNpmTasks('grunt-shell-spawn'); + grunt.loadNpmTasks('grunt-wait'); + grunt.loadNpmTasks('grunt-contrib-copy'); + grunt.loadNpmTasks('grunt-contrib-connect'); + grunt.initConfig({ + connect: { + server: { + options: { + port: 8000, + base: './', + middleware: function(connect, options, middlewares) { + middlewares.unshift(function(req, res, next) { + if (req.method.toUpperCase() == 'POST' || req.method.toUpperCase() == "PUT" || + req.method.toUpperCase() == "DELETE") + { + req.method='GET'; + } + return next(); + }); + return middlewares; + } + } + } + }, + copy: { + assets: { + expand: true, + cwd: '../../3rd_party/static/testapi-ui/assets', + src: '**', + dest: 'testapi-ui/assets', + }, + components: { + expand: true, + cwd: 'components', + src: '**', + dest: 'testapi-ui/components', + }, + shared: { + expand: true, + cwd: 'shared', + src: '**', + dest: 'testapi-ui/shared', + }, + filesPng: { + expand: true, + src: '*.png', + dest: 'testapi-ui/', + }, + filesIco: { + expand: true, + src: '*.ico', + dest: 'testapi-ui/', + }, + filesJs: { + expand: true, + src: 'app.js', + dest: 'testapi-ui/', + }, + filesJson: { + expand: true, + src: 'config.json', + dest: 'testapi-ui/', + } + }, + wait: { + default: { + options: { + delay: 3000 + } + } + }, + shell: { + updateSelenium: { + command: 'node_modules/protractor/bin/webdriver-manager update', + options: { + async: false + } + }, + startSelenium: { + command: 'node_modules/protractor/bin/webdriver-manager start', + options: { + async: true + } + }, + deleteFiles: { + command: 'rm -r testapi-ui', + options: { + async: false + } + }, + options: { + stdout: false, + stderr: false + } + }, + instrument: { + files: ['components/**/*.js'], + options: { + lazy: false, + basePath: "./testapi-ui/" + } + }, + karma: { + unit: { + configFile: 'karma.conf.js' + } + }, + protractor_coverage: { + options: { + keepAlive: true, + noColor: false, + coverageDir: '../tests/UI/coverage', + args: { + specs: [ + '../tests/UI/e2e/homeControllerSpec.js', + '../tests/UI/e2e/podsControllerSpec.js', + '../tests/UI/e2e/projectsControllerSpec.js', + '../tests/UI/e2e/testCasesControllerSpec.js', + '../tests/UI/e2e/resultsControllerSpec.js', + '../tests/UI/e2e/scenariosControllerSpec.js', + '../tests/UI/e2e/scenarioControllerSpec.js' + ] + } + }, + local: { + options: { + configFile: '../tests/UI/protractor-conf.js' + } + } + }, + makeReport: { + src: '../tests/UI/coverage/*.json', + options: { + print: 'detail' + } + } + }); + grunt.registerTask('test', [ + 'karma:unit' + ]); + grunt.registerTask('e2e', [ + 'copy:assets', + 'copy:components', + 'copy:shared', + 'copy:filesPng', + 'copy:filesIco', + 'copy:filesJs', + 'copy:filesJson', + 'instrument', + 'connect', + 'shell:updateSelenium', + 'shell:startSelenium', + 'wait:default', + 'protractor_coverage', + 'makeReport', + 'shell:deleteFiles' + ]); } diff --git a/testapi/opnfv_testapi/ui/app.js b/testapi/opnfv_testapi/ui/app.js index 28e5810..c2fa774 100644 --- a/testapi/opnfv_testapi/ui/app.js +++ b/testapi/opnfv_testapi/ui/app.js @@ -79,11 +79,31 @@ templateUrl: 'testapi-ui/components/projects/project/project.html', controller: 'ProjectController as ctrl' }). + state('scenarios', { + url: '/scenarios', + templateUrl: 'testapi-ui/components/scenarios/scenarios.html', + controller: 'ScenariosController as ctrl' + }). + state('scenario', { + url: '/scenarios/:name', + templateUrl: 'testapi-ui/components/scenarios/scenario/scenario.html', + controller: 'ScenarioController as ctrl' + }). + state('testCase', { + url: '/projects/:project_name/:name', + templateUrl: 'testapi-ui/components/projects/project/testCases/testCase/testCase.html', + controller: 'TestCaseController as ctrl' + }). state('results', { url: '/results', templateUrl: 'testapi-ui/components/results/results.html', controller: 'ResultsController as ctrl' }). + state('result', { + url: '/result/:_id', + templateUrl: 'testapi-ui/components/results/result/result.html', + controller: 'ResultController as ctrl' + }). state('profile', { url: '/profile', templateUrl: 'testapi-ui/components/profile/profile.html', @@ -124,16 +144,17 @@ .run(setup); setup.$inject = [ - '$http', '$rootScope', '$window', '$state', 'testapiApiUrl' + '$http', '$rootScope', '$window', '$state', 'testapiApiUrl', "authenticate" ]; /** * Set up the app with injections into $rootscope. This is mainly for auth * functions. */ - function setup($http, $rootScope, $window, $state, testapiApiUrl) { + function setup($http, $rootScope, $window, $state, testapiApiUrl, authenticate) { $rootScope.auth = {}; + $rootScope.authenticate = authenticate $rootScope.auth.doSignIn = doSignIn; $rootScope.auth.doSignOut = doSignOut; $rootScope.auth.doSignCheck = doSignCheck; @@ -150,10 +171,14 @@ /** This function will initate a sign out. */ function doSignOut() { - $rootScope.auth.currentUser = null; - $rootScope.auth.isAuthenticated = false; - $rootScope.auth.projectNames = []; - $window.location.href = sign_out_url; + if(authenticate){ + $rootScope.auth.currentUser = null; + $rootScope.auth.isAuthenticated = false; + $rootScope.auth.projectNames = []; + $window.location.href = sign_out_url; + }else{ + $state.go("home", {reload: true}) + } } /** @@ -161,17 +186,23 @@ * authenticated. */ function doSignCheck() { - return $http.get(profile_url, {withCredentials: true}). - success(function (data) { - $rootScope.auth.currentUser = data; - $rootScope.auth.isAuthenticated = true; - $rootScope.auth.projectNames = $rootScope.auth.doSubmitterCheck(data.groups); - }). - error(function () { - $rootScope.auth.currentUser = null; - $rootScope.auth.isAuthenticated = false; - $rootScope.auth.projectNames = []; - }); + if(authenticate){ + return $http.get(profile_url, {withCredentials: true}). + success(function (data) { + $rootScope.auth.currentUser = data; + $rootScope.auth.isAuthenticated = true; + $rootScope.auth.projectNames = $rootScope.auth.doSubmitterCheck(data.groups); + }). + error(function () { + $rootScope.auth.currentUser = null; + $rootScope.auth.isAuthenticated = false; + $rootScope.auth.projectNames = []; + }); + }else{ + $rootScope.auth.currentUser = null; + $rootScope.auth.isAuthenticated = true; + $rootScope.auth.projectNames = [] + } } function doSubmitterCheck(groups){ diff --git a/testapi/opnfv_testapi/ui/components/pods/pods.html b/testapi/opnfv_testapi/ui/components/pods/pods.html index 02f4a48..4fa8fb1 100644 --- a/testapi/opnfv_testapi/ui/components/pods/pods.html +++ b/testapi/opnfv_testapi/ui/components/pods/pods.html @@ -22,14 +22,7 @@ </div> <div class="col-sm-3 pull-right"> <span style="margin-top:6px">Search: </span> - <input type="text" class="form-control search" ngModel="filter" placeholder="Search String"> - </div> - <div class="col-md-3 row pull-right"> - <span style="margin-top:6px">Filter: </span> - <select ng-model="ctrl.filter" class="form-control"> - <option value="name">Name</option> - <option value="owner">Owner</option> - </select> + <input type="text" class="form-control search" ng-Model="ctrl.filterText" placeholder="Search String"> </div> </div> <div class="col-md-12"> @@ -48,11 +41,11 @@ <thead> <tr style=" text-align: center;"> - <th>Bulk Select</th> + <th style="width:1%">Bulk Select</th> <th>Name</th> <th>Role</th> <th>Mode</th> - <th>Operation</th> + <th ng-class="{ 'hidden': !auth.isAuthenticated }">Operation</th> </tr> </thead> <tbody> @@ -62,16 +55,13 @@ <input type="checkbox" value="{{pod.name}}" ng-model="ctrl.checkBox[index]" > </div> </td> - <td>{{pod.name}}</td> + <td><a class="text-info" ng-click="ctrl.viewPod(pod.name)">{{pod.name}}</a></td> <td>{{pod.role}}</td> <td>{{pod.mode}}</td> - <td> + <td ng-class="{ 'hidden': !auth.isAuthenticated }"> <span class="podsTable-col"> - <a class="text-warning" title="Edit" ng-class="{ 'hidden': !auth.isAuthenticated }" > - <i class="fa fa-pencil-square-o"></i></a> <a class="text-danger" ng-click="ctrl.openDeleteModal(pod.name)" title="Delete" ng-class="{ 'hidden': !auth.isAuthenticated }"> <i class="fa fa-trash-o"></i></a> - <a class="text-info" ng-click="ctrl.viewPod(pod.name)"><i class="fa fa-eye"></i></a> </span> </td> </tr> diff --git a/testapi/opnfv_testapi/ui/components/pods/podsController.js b/testapi/opnfv_testapi/ui/components/pods/podsController.js index c66873a..95e3571 100644 --- a/testapi/opnfv_testapi/ui/components/pods/podsController.js +++ b/testapi/opnfv_testapi/ui/components/pods/podsController.js @@ -40,13 +40,13 @@ ctrl.listPods = listPods; ctrl.open = open; ctrl.filter = 'name' - ctrl.clearFilters = clearFilters; ctrl.openDeleteModal = openDeleteModal ctrl.openBatchDeleteModal = openBatchDeleteModal ctrl.openCreateModal = openCreateModal ctrl.podDelete = podDelete ctrl.batchDelete = batchDelete; ctrl.viewPod = viewPod + ctrl.filterText = '' /** * This is called when the date filter calendar is opened. It @@ -61,13 +61,6 @@ ctrl[openVar] = true; } - /** - * This function will clear all filters and update the results - * listing. - */ - function clearFilters() { - ctrl.listPods(); - } /** * This will contact the TestAPI to create a new pod. @@ -91,7 +84,7 @@ ctrl.listPods(); }).catch(function (data) { ctrl.showError = true; - ctrl.error = "Error creating the new pod from server: " + data.statusText; + ctrl.error = data.statusText; }); } else{ @@ -105,21 +98,21 @@ */ function listPods() { ctrl.showError = false; + var reqURL = ctrl.url; + if(ctrl.filterText!=''){ + reqURL = ctrl.url + "?name=" + ctrl.filterText + } ctrl.podsRequest = - $http.get(ctrl.url).success(function (data) { + $http.get(reqURL).success(function (data) { ctrl.data = data; - // mapNametoRandom - }).error(function (error) { + }).catch(function (data) { ctrl.data = null; ctrl.showError = true; - ctrl.error = - 'Error retrieving pods from server: ' + - angular.toJson(error); + ctrl.error = data.statusText; }); } function viewPod(name){ - console.log('hello'); $state.go('pod', {'name':name}, {reload: true}); } /** @@ -192,22 +185,6 @@ }); } - // function openUpdateModal(podName){ - // $uibModal.open({ - // templateUrl: 'testapi-ui/components/pods/modals/createModal.html', - // controller: 'PodModalCtrl as PodModalCtrl', - // size: 'md', - // resolve: { - // data: function () { - // return { - // text: "Update", - // successHandler: ctrl.update, - // // pod: ctrl. - // }; - // } - // } - // }); - // } ctrl.listPods(); } diff --git a/testapi/opnfv_testapi/ui/components/profile/profileController.js b/testapi/opnfv_testapi/ui/components/profile/profileController.js index 5dbdf7b..e34e745 100644 --- a/testapi/opnfv_testapi/ui/components/profile/profileController.js +++ b/testapi/opnfv_testapi/ui/components/profile/profileController.js @@ -35,7 +35,7 @@ ProfileController.$inject = [ '$scope', '$http', 'testapiApiUrl', 'PubKeys', - '$uibModal', 'raiseAlert', '$state' + '$uibModal', 'raiseAlert', '$state' , 'authenticate' ]; /** @@ -44,7 +44,7 @@ * account-specific information. */ function ProfileController($scope, $http, testapiApiUrl, - PubKeys, $uibModal, raiseAlert, $state) { + PubKeys, $uibModal, raiseAlert, $state, authenticate) { var ctrl = this; @@ -53,7 +53,7 @@ ctrl.openShowPubKeyModal = openShowPubKeyModal; // Must be authenticated to view this page. - if (!$scope.auth.isAuthenticated) { + if (!$scope.auth.isAuthenticated || !authenticate) { $state.go('home'); } @@ -115,8 +115,9 @@ ctrl.updatePubKeys(); }); } - - ctrl.authRequest = $scope.auth.doSignCheck().then(ctrl.updatePubKeys); + if(authenticate){ + ctrl.authRequest = $scope.auth.doSignCheck().then(ctrl.updatePubKeys); + } } angular diff --git a/testapi/opnfv_testapi/ui/components/projects/modals/projectModal.html b/testapi/opnfv_testapi/ui/components/projects/modals/projectModal.html new file mode 100644 index 0000000..ca00f80 --- /dev/null +++ b/testapi/opnfv_testapi/ui/components/projects/modals/projectModal.html @@ -0,0 +1,39 @@ +<div class="ball" style="padding:5px;"> + <div class="modal-body"> + <div class="form-horizontal"> + <fieldset> + <div class="form-group"> + <legend>{{ProjectModalCtrl.data.text}}</legend> + <div class="row"> + <div ng-repeat="require in ProjectModalCtrl.createRequirements" style="margin-left:15px"> + <div class="update-project"> + <label for="cpid" class="control-label col-sm-2">{{require.label|capitalize}}: </label> + <div class="col-sm-9"> + <a ng-if="require.type == 'select'"> + <select class="form-control" dynamic-model="'ProjectModalCtrl.project.' + require.label" ng-options="option for option in require.selects"></select> + </a> + <a ng-if="require.type == 'text'"> + <input type="text" class="form-control" dynamic-model="'ProjectModalCtrl.project.' + require.label"/> + </a> + <a ng-if="require.type == 'textarea'"> + <textarea rows="2" class="form-control" cols="50" dynamic-model="'ProjectModalCtrl.project.' + require.label"> + </textarea> + </a> + <p class="help-block"></p> + </div> + </div> + </div> + </div> + </div> + </fieldset> + </div> + </div> + <div class="modal-footer"> + <div ng-show="ProjectModalCtrl.showCreateError" style="padding:0px;" class="col-md-6 alert alert-danger" role="alert"> + <span class="pull-right"> {{ProjectModalCtrl.error}}</span> + <span class="glyphicon glyphicon-exclamation-sign pull-right" aria-hidden="true" >Error:</span> + </div> + <button class="btn btn-primary" ng-click="ProjectModalCtrl.confirm()">Ok</button> + <button class="btn btn-default" ng-click="ProjectModalCtrl.cancel()">Cancel</button> + </div> +</div>
\ No newline at end of file diff --git a/testapi/opnfv_testapi/ui/components/projects/project/project.html b/testapi/opnfv_testapi/ui/components/projects/project/project.html index 9d46364..2921bd9 100644 --- a/testapi/opnfv_testapi/ui/components/projects/project/project.html +++ b/testapi/opnfv_testapi/ui/components/projects/project/project.html @@ -1,25 +1,56 @@ -<div ng-show="ctrl.data" class="projects-table" style="margin-top:24px; margin-left:8px;"> - <table class="table"> - <tbody> - <tr> <td class="col-md-3">Name</td> <td class="col-md-9">{{ctrl.data.name}}</td> </tr> - <tr> <td>Description</td> <td>{{ctrl.data.description}}</td> </tr> - <tr> <td>Creation date</td> <td>{{ctrl.data.creation_date}}</td> </tr> - </tbody> - </table> -</div> - +<legend>Project</legend> <div class="row" style="margin-bottom:24px;"></div> -<div class="project-create col-md-3" style="margin-top:10px" ng-class="{ 'hidden': ! ((auth.projectNames.length>0) && - auth.isAuthenticated) }"> - <button type="submit" class="btn btn-primary" ng-click="ctrl.openDeleteModal()">Delete Project</button> - <button type="submit" class="btn btn-primary" ng-click="ctrl.openUpdateModal()">Update Project</button> + +<div class="tabbable tabs-below" ng-init="selectedTab = 1;"> + <ul class="nav nav-tabs nav-justified" style="width:30%"> + <li ng-class="{active: selectedTab == 1}"> + <a ng-click="selectedTab = 1;">Overview</a> + </li> + <li ng-class="{active: selectedTab == 2}"> + <a ng-click="selectedTab = 2;">Test Cases</a> + </li> + </ul> + + <div class="tab-content" ng-show="selectedTab == 1"> + <div style="padding-right:0px; margin-top:20px" > + <div class="table-responsive"> + <table class="table" ng-data="ctrl.data.pods"> + <tbody> + <tr style="padding:9px"> + <td class="podsTableTd">Id :</td> + <td class="podsTableLeftTd">{{ctrl.data._id}}</td> + </tr> + <tr style="padding:9px"> + <td class="podsTableTd">Name :</td> + <td width="90%" class="podsTableLeftTd">{{ctrl.data.name}}</td> + </tr> + <tr style="padding:9px"> + <td class="podsTableTd">Owner :</td> + <td width="90%" class="podsTableLeftTd">{{ctrl.data.owner}}</td> + </tr> + <tr style="padding:9px"> + <td class="podsTableTd">Created at :</td> + <td width="90%" class="podsTableLeftTd">{{ctrl.data['creation_date']}}</td> + </tr> + <tr style="padding:9px"> + <td class="podsTableTd">Description :</td> + <td width="90%" class="podsTableLeftTd">{{ctrl.data.description}}</td> + </tr> + </tbody> + </table> + </div> + </div> + </div> + <div class="tab-content" ng-show="selectedTab == 2"> + <div ng-include src="'testapi-ui/components/projects/project/testCases/testCases.html'"></div> + </div> </div> -<div ng-show="ctrl.showError" class="alert alert-danger col-md-9" role="alert"> +<div ng-show="ctrl.showError" class="alert alert-danger col-md-9" role="alert" style="margin-top:0px"> <span class="glyphicon glyphicon-exclamation-sign" aria-hidden="true"></span> <span class="sr-only">Error:</span> {{ctrl.error}} </div> -<div ng-show="ctrl.showSuccess" class="alert alert-success col-md-9" role="alert"> +<div ng-show="ctrl.showSuccess" class="alert alert-success col-md-9" role="alert" style="margin-top:0px"> <span class="glyphicon glyphicon-ok" aria-hidden="true"></span> Update Success -</div>
\ No newline at end of file +</div> diff --git a/testapi/opnfv_testapi/ui/components/projects/project/projectController.js b/testapi/opnfv_testapi/ui/components/projects/project/projectController.js index 8f4bd20..78b805d 100644 --- a/testapi/opnfv_testapi/ui/components/projects/project/projectController.js +++ b/testapi/opnfv_testapi/ui/components/projects/project/projectController.js @@ -36,88 +36,6 @@ ctrl.url = testapiApiUrl + '/projects/' + ctrl.name; ctrl.loadDetails = loadDetails; - ctrl.deleteProject = deleteProject; - ctrl.openDeleteModal = openDeleteModal; - ctrl.openUpdateModal = openUpdateModal; - ctrl.updateProject = updateProject; - - - /** - * This will contact the TestAPI to update an existing project. - */ - function updateProject(name,description) { - ctrl.showError = false; - ctrl.showSuccess = false; - if(ctrl.name != ""){ - var projects_url = ctrl.url; - var body = { - name: name, - description: description - }; - ctrl.projectsRequest = - $http.put(projects_url, body).success(function (data){ - ctrl.showSuccess = true ; - }) - .error(function (data) { - ctrl.showError = true; - ctrl.error = 'Error updating the existing Project from server: ' + angular.toJson(data); - }); - ctrl.name = ""; - ctrl.description=""; - } - else{ - ctrl.showError = true; - ctrl.error = 'Name is missing.' - } - } - - /** - * This will contact the TestAPI to delete an existing project. - */ - function deleteProject() { - ctrl.showError = false; - ctrl.showSuccess = false; - ctrl.projectsRequest = - $http.delete(ctrl.url).success(function (data) { - $state.go('projects', {}, {reload: true}); - ctrl.showSuccess = true ; - - }).error(function (error) { - ctrl.showError = true; - ctrl.error = - 'Error deleting project from server: ' + - angular.toJson(error); - }); - } - - /** - * This will open the modal that will show the delete confirm - * message - */ - function openDeleteModal() { - confirmModal("Delete",ctrl.deleteProject); - } - - /** - * This will open the modal that will show the update - * view - */ - function openUpdateModal(){ - $uibModal.open({ - templateUrl: 'testapi-ui/components/projects/project/updateModal.html', - controller: 'ModalInstanceCtrl as updateModal', - size: 'md', - resolve: { - data: function () { - return { - text: "Update", - successHandler: ctrl.updateProject, - project: ctrl.data - }; - } - } - }); - } /** * This will contact the TestAPI to get a listing of declared projects. @@ -127,57 +45,12 @@ ctrl.projectsRequest = $http.get(ctrl.url).success(function (data) { ctrl.data = data; - }).error(function (error) { + }).catch(function (error) { ctrl.data = null; ctrl.showError = true; - ctrl.error = - 'Error retrieving projects from server: ' + - angular.toJson(error); + ctrl.error = error.statusText }); } ctrl.loadDetails(); } - - - /** - * TestAPI Modal instance Controller - * This controller is for the update modal where a user can update - * the project information. - */ - angular.module('testapiApp').controller('ModalInstanceCtrl', ModalInstanceCtrl); - ModalInstanceCtrl.$inject = ['$scope', '$uibModalInstance', 'data']; - function ModalInstanceCtrl($scope, $uibModalInstance, data) { - var ctrl = this; - ctrl.confirm = confirm; - ctrl.cancel = cancel; - ctrl.data = angular.copy(data); - - ctrl.createRequirements = [ - {label: 'name', type: 'text', required: true}, - {label: 'description', type: 'textarea', required: false} - ]; - - ctrl.name = ctrl.data.project.name; - ctrl.description = ctrl.data.project.description; - - /** - * Initiate confirmation and call the success handler with the - * inputs. - */ - function confirm() { - $uibModalInstance.close(); - if (angular.isDefined(ctrl.data.successHandler)) { - ctrl.data.successHandler(ctrl.name,ctrl.description); - } - } - - /** - * Close the confirm modal without initiating changes. - */ - function cancel() { - $uibModalInstance.dismiss('cancel'); - } - } - - })(); diff --git a/testapi/opnfv_testapi/ui/components/projects/project/testCases/modals/testCaseModal.html b/testapi/opnfv_testapi/ui/components/projects/project/testCases/modals/testCaseModal.html new file mode 100644 index 0000000..d1c9cb5 --- /dev/null +++ b/testapi/opnfv_testapi/ui/components/projects/project/testCases/modals/testCaseModal.html @@ -0,0 +1,39 @@ +<div class="ball" style="padding:5px;"> + <div class="modal-body"> + <div class="form-horizontal"> + <fieldset> + <div class="form-group"> + <legend>{{TestCaseModalCtrl.data.text}}</legend> + <div class="row"> + <div ng-repeat="require in TestCaseModalCtrl.createRequirements" style="margin-left:15px"> + <div class="update-project"> + <label for="cpid" class="control-label col-sm-3">{{require.label.replace("_"," ")|capitalize}}: </label> + <div class="col-sm-8"> + <a ng-if="require.type == 'select'"> + <select class="form-control" dynamic-model="'TestCaseModalCtrl.testcase.' + require.label" ng-options="option for option in require.selects"></select> + </a> + <a ng-if="require.type == 'text'"> + <input type="text" class="form-control" dynamic-model="'TestCaseModalCtrl.testcase.' + require.label"/> + </a> + <a ng-if="require.type == 'textarea'"> + <textarea rows="2" class="form-control" cols="50" dynamic-model="'TestCaseModalCtrl.testcase.' + require.label"> + </textarea> + </a> + <p class="help-block"></p> + </div> + </div> + </div> + </div> + </div> + </fieldset> + </div> + </div> + <div class="modal-footer"> + <div ng-show="TestCaseModalCtrl.showCreateError" style="padding:0px;" class="col-md-6 alert alert-danger" role="alert"> + <span class="pull-right"> {{TestCaseModalCtrl.error}}</span> + <span class="glyphicon glyphicon-exclamation-sign pull-right" aria-hidden="true" >Error:</span> + </div> + <button class="btn btn-primary" ng-click="TestCaseModalCtrl.confirm()">Ok</button> + <button class="btn btn-default" ng-click="TestCaseModalCtrl.cancel()">Cancel</button> + </div> +</div>
\ No newline at end of file diff --git a/testapi/opnfv_testapi/ui/components/projects/project/testCases/testCase/testCase.html b/testapi/opnfv_testapi/ui/components/projects/project/testCases/testCase/testCase.html new file mode 100644 index 0000000..70c026a --- /dev/null +++ b/testapi/opnfv_testapi/ui/components/projects/project/testCases/testCase/testCase.html @@ -0,0 +1,80 @@ +<legend>Test Case</legend> +<div style="padding-right:0px"> + <div class="table-responsive"> + <table class="table" ng-data="ctrl.data"> + <tbody> + <tr style="padding:9px"> + <td class="podsTableTd">Id :</td> + <td class="podsTableLeftTd">{{ctrl.data._id}}</td> + </tr> + <tr style="padding:9px"> + <td class="podsTableTd">Name :</td> + <td width="90%" class="podsTableLeftTd">{{ctrl.data.name}}</td> + </tr> + <tr style="padding:9px"> + <td class="podsTableTd">Project :</td> + <td width="90%" class="podsTableLeftTd">{{ctrl.data.project_name}}</td> + </tr> + <tr style="padding:9px"> + <td class="podsTableTd">Tier :</td> + <td width="90%" class="podsTableLeftTd">{{ctrl.data.tier}}</td> + </tr> + <tr style="padding:9px"> + <td class="podsTableTd">Blocking :</td> + <td width="90%" class="podsTableLeftTd">{{ctrl.data.blocking}}</td> + </tr> + <tr style="padding:9px"> + <td class="podsTableTd">CI Loop :</td> + <td width="90%" class="podsTableLeftTd">{{ctrl.data.ci_loop}}</td> + </tr> + <tr style="padding:9px"> + <td class="podsTableTd">Tags :</td> + <td width="90%" class="podsTableLeftTd">{{ctrl.data.tags}}</td> + </tr> + <tr style="padding:9px"> + <td class="podsTableTd">Version :</td> + <td width="90%" class="podsTableLeftTd">{{ctrl.data.version}}</td> + </tr> + <tr style="padding:9px"> + <td class="podsTableTd">Created at :</td> + <td width="90%" class="podsTableLeftTd">{{ctrl.data['creation_date']}}</td> + </tr> + <tr style="padding:9px"> + <td class="podsTableTd">Dependencies :</td> + <td width="90%" class="podsTableLeftTd">{{ctrl.data.dependencies}}</td> + </tr> + <tr style="padding:9px"> + <td class="podsTableTd">Trust :</td> + <td width="90%" class="podsTableLeftTd">{{ctrl.data.trust}}</td> + </tr> + <tr style="padding:9px"> + <td class="podsTableTd">Criteria :</td> + <td width="90%" class="podsTableLeftTd">{{ctrl.data.criteria}}</td> + </tr> + <tr style="padding:9px"> + <td class="podsTableTd">Catalog Description :</td> + <td width="90%" class="podsTableLeftTd">{{ctrl.data.catalog_description}}</td> + </tr> + <tr style="padding:9px"> + <td class="podsTableTd">URL :</td> + <td width="90%" class="podsTableLeftTd">{{ctrl.data.url}}</td> + </tr> + <tr style="padding:9px"> + <td class="podsTableTd">Run :</td> + <td width="90%" class="podsTableLeftTd">{{ctrl.data.run}}</td> + </tr> + <tr style="padding:9px"> + <td class="podsTableTd">Description :</td> + <td width="90%" class="podsTableLeftTd">{{ctrl.data.description}}</td> + </tr> + </tbody> + </table> + </div> +</div> +<div class="row" style="margin-bottom:24px;"></div> +<div ng-show="ctrl.showError" class="alert alert-danger col-md-8" role="alert" style="margin-top:0px"> + <span class="glyphicon glyphicon-exclamation-sign" aria-hidden="true"></span> + <span class="sr-only">Error:</span> + {{ctrl.error}} +</div> +<div class="row" style="margin-bottom:24px;"></div>
\ No newline at end of file diff --git a/testapi/opnfv_testapi/ui/components/projects/project/testCases/testCase/testCaseController.js b/testapi/opnfv_testapi/ui/components/projects/project/testCases/testCase/testCaseController.js new file mode 100644 index 0000000..a38b633 --- /dev/null +++ b/testapi/opnfv_testapi/ui/components/projects/project/testCases/testCase/testCaseController.js @@ -0,0 +1,57 @@ +/* + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +(function () { + 'use strict'; + + angular + .module('testapiApp') + .controller('TestCaseController', TestCaseController); + + TestCaseController.$inject = [ + '$scope', '$http', '$filter', '$state', '$window', '$uibModal', 'testapiApiUrl','raiseAlert', + 'confirmModal' + ]; + + /** + * TestAPI Project Controller + * This controller is for the '/projects' page where a user can browse + * through projects declared in TestAPI. + */ + function TestCaseController($scope, $http, $filter, $state, $window, $uibModal, testapiApiUrl, + raiseAlert, confirmModal) { + var ctrl = this; + ctrl.name = $state.params['name']; + ctrl.projectName = $state.params['project_name']; + ctrl.url = testapiApiUrl + '/projects/' + ctrl.projectName + "/cases/" + ctrl.name; + + ctrl.loadDetails = loadDetails; + + /** + * This will contact the TestAPI to get a listing of declared projects. + */ + function loadDetails() { + ctrl.showError = false; + ctrl.projectsRequest = + $http.get(ctrl.url).success(function (data) { + ctrl.data = data; + }).catch(function (error) { + ctrl.data = null; + ctrl.showError = true; + ctrl.error = error.statusText + }); + } + ctrl.loadDetails(); + } +})(); diff --git a/testapi/opnfv_testapi/ui/components/projects/project/testCases/testCases.html b/testapi/opnfv_testapi/ui/components/projects/project/testCases/testCases.html new file mode 100644 index 0000000..ee87e0a --- /dev/null +++ b/testapi/opnfv_testapi/ui/components/projects/project/testCases/testCases.html @@ -0,0 +1,68 @@ +<div ng-controller="TestCasesController as testCasesCtrl" class="col-md-12"> +<div class="row podsTable" style="vertical-align:middle"> + <div class="col-sm-1 pull-right" ng-class="{ 'hidden': ! ((auth.projectNames.length>0) && + auth.isAuthenticated) }" > + <button type="button" class="btn btn-danger" ng-click="testCasesCtrl.openBatchDeleteModal()"> + <i class="fa fa-minus"></i> Delete</button> + </div> + <div class="col-sm-1 pull-right" ng-class="{ 'hidden': ! ((auth.projectNames.length>0) && + auth.isAuthenticated) }"> + <button type="button" class="btn btn-success" ng-click="testCasesCtrl.openCreateModal()"> + <i class="fa fa-plus"></i> Create</button> + </div> +</div> +<div class='clo-md-12'> + <div ng-show="testCasesCtrl.showError" class="alert alert-danger" role="alert"> + <span class="pull-right"> {{testCasesCtrl.error}}</span> + <span class="glyphicon glyphicon-exclamation-sign pull-right" aria-hidden="true" >Error:</span> + </div> + <div ng-show="testCasesCtrl.showSuccess" class="alert alert-success" role="alert"> + <span class="pull-right"> {{testCasesCtrl.successMessage}}</span> + <span class="glyphicon glyphicon-ok pull-right" aria-hidden="true"></span> + </div> +</div> +<div class='clo-md-12' style="padding-right:0px"> + <div class="table-responsive"> + <table class="table table-bordered table-hover" ng-data="testCasesCtrl.data.testcases"> + <thead> + <tr style=" + text-align: center;"> + <th style="width: 1%;">Bulk Select</th> + <th style="width: 19%;">Name</th> + <th style="width: 20%;">Tier</th> + <th style="width: 20%;">Blocking</th> + <th style="width: 20%;">CI Loop</th> + <th style="width: 20%;" ng-class="{'hidden': ! ((auth.projectNames.length>0) && auth.isAuthenticated)}">Operations</th> + </tr> + </thead> + <tbody> + <tr ng-repeat-start="(index, testcase) in testCasesCtrl.data.testcases" style="padding:9px"> + <td> + <div class="text-center"> + <input type="checkbox" value="{{project.name}}" ng-model="testCasesCtrl.checkBox[index]" > + </div> + </td> + <td> + <a class="text-info" ng-click="testCasesCtrl.viewTestCase(testcase.name, testcase.project_name)"> + {{testcase.name}} + </a> + </td> + <td>{{testcase.tier}}</td> + <td>{{testcase.blocking}}</td> + <td>{{testcase.ci_loop}}</td> + <td ng-class="{'hidden': ! ((auth.projectNames.length>0) && auth.isAuthenticated)}"> + <span class="podsTable-col"> + <a class="text-warning" ng-click="testCasesCtrl.openUpdateTestModal(testcase.name)" title="Edit"> + <i class="fa fa-pencil-square-o"></i></a> + <a class="text-danger" ng-click="testCasesCtrl.openDeleteTestModal(testcase.name)" title="Delete"> + <i class="fa fa-trash-o"></i></a> + </span> + </td> + </tr> + <tr ng-repeat-end=> + </tr> + </tbody> + </table> + </div> +</div> +</div> diff --git a/testapi/opnfv_testapi/ui/components/projects/project/testCases/testCasesController.js b/testapi/opnfv_testapi/ui/components/projects/project/testCases/testCasesController.js new file mode 100644 index 0000000..6d3c245 --- /dev/null +++ b/testapi/opnfv_testapi/ui/components/projects/project/testCases/testCasesController.js @@ -0,0 +1,279 @@ +/* + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +(function () { + 'use strict'; + + angular + .module('testapiApp') + .controller('TestCasesController', TestCasesController); + + TestCasesController.$inject = [ + '$scope', '$http', '$filter', '$state', '$window', '$uibModal', 'testapiApiUrl','raiseAlert', + 'confirmModal' + ]; + + /** + * TestAPI Test cases Controller + * This controller is for the tescases page where a user can browse + * through testcases declared in TestAPI and perform the CRUD operations + * in them. + */ + function TestCasesController($scope, $http, $filter, $state, $window, $uibModal, testapiApiUrl, + raiseAlert, confirmModal) { + var ctrl = this; + ctrl.loadDetails = loadDetails; + ctrl.name = $state.params['name']; + ctrl.requestUrl = testapiApiUrl + '/projects/' + ctrl.name +'/cases'; + + ctrl.createTestCase = createTestCase; + ctrl.openCreateModal = openCreateModal; + ctrl.deleteTestCase = deleteTestCase; + ctrl.openDeleteTestModal = openDeleteTestModal; + ctrl.updateTestCase = updateTestCase; + ctrl.openUpdateTestModal = openUpdateTestModal; + ctrl.batchDelete = batchDelete; + ctrl.openBatchDeleteModal = openBatchDeleteModal; + ctrl.viewTestCase = viewTestCase; + + ctrl.checkBox = []; + ctrl.checkBoxList = []; + + /** + * This will contact the TestAPI to create a new test case. + */ + function createTestCase(name, testcase) { + ctrl.showError = false; + ctrl.showSuccess = false; + if(testcase.name != "" && testcase.name!=null){ + var testCase_url = ctrl.requestUrl; + ctrl.testCasesRequest = + $http.post(testCase_url, testcase).success(function (data){ + ctrl.showSuccess = true ; + ctrl.successMessage = "Testcase is successfully created." + loadDetails(); + }) + .catch(function (data) { + ctrl.showError = true; + ctrl.error = data.statusText; + }); + } + else{ + ctrl.showError = true; + ctrl.error = 'Name is missing.' + } + } + + function viewTestCase(name, project_name){ + $state.go('testCase', {'name':name, 'project_name':project_name}, {reload: true}); + } + + /** + * This will open the modal that will show the batch delete confirm + * message + */ + function openBatchDeleteModal() { + confirmModal("Delete",ctrl.batchDelete); + } + + /** + * This will delete list of test cases. + */ + function batchDelete(){ + var index; + var checkedBox = []; + ctrl.checkBox.forEach(function(testcase, index){ + if(!ctrl.showError){ + if(testcase){ + ctrl.deleteTestCase(ctrl.data.testcases[index].name); + } + } + }); + ctrl.checkBox = [] + } + /** + * This will contact the TestAPI to update an existing test case. + */ + function updateTestCase(name, testCase) { + ctrl.showError = false; + ctrl.showSuccess = false; + if(testCase.name != ""){ + var testCase_url = ctrl.requestUrl + '/' + name; + ctrl.testCasesRequest = + $http.put(testCase_url, testCase).success(function (data){ + ctrl.showSuccess = true ; + ctrl.successMessage = "Test case is successfully updated" + loadDetails(); + }) + .catch(function (data) { + ctrl.showError = true; + ctrl.error = data.statusText; + }); + } + else{ + ctrl.showError = true; + ctrl.error = 'Name is missing.' + } + } + + /** + * This will contact the TestAPI to delete an existing test case. + */ + function deleteTestCase(name) { + ctrl.showError = false; + ctrl.showSuccess = false; + ctrl.testCasesRequest = + $http.delete(ctrl.requestUrl+"/"+name).success(function (data) { + loadDetails(); + ctrl.showSuccess = true ; + ctrl.successMessage = "Test case is successfully deleted" + }).catch(function (error) { + ctrl.showError = true; + ctrl.error = data.statusText; + }); + } + + /** + * This will open the modal that will show the delete confirm + * message + */ + function openDeleteTestModal(name) { + confirmModal("Delete", ctrl.deleteTestCase, name); + } + + /** + * This will open the modal that will show the Create + * view + */ + function openCreateModal(name){ + $uibModal.open({ + templateUrl: 'testapi-ui/components/projects/project/testCases/modals/testCaseModal.html', + controller: 'TestCaseModalCtrl as TestCaseModalCtrl', + size: 'md', + resolve: { + data: function () { + return { + text: "Create", + successHandler: ctrl.createTestCase + }; + } + } + }); + } + + /** + * This will open the modal that will show the update + * view + */ + function openUpdateTestModal(name){ + var testcase; + var index; + for(index in ctrl.data.testcases){ + if(ctrl.data.testcases[index].name==name){ + testcase = ctrl.data.testcases[index] + continue + } + } + $uibModal.open({ + templateUrl: 'testapi-ui/components/projects/project/testCases/modals/testCaseModal.html', + controller: 'TestCaseModalCtrl as TestCaseModalCtrl', + size: 'md', + resolve: { + data: function () { + return { + text: "Update", + successHandler: ctrl.updateTestCase, + testCase: testcase + }; + } + } + }); + } + + /** + * This will contact the TestAPI to get a listing of declared test cases. + */ + function loadDetails() { + ctrl.testCasesReguest = + $http.get(ctrl.requestUrl).success(function (data) { + ctrl.data = data; + }).catch(function (error) { + ctrl.data = null; + ctrl.showError = true; + ctrl.error = error.statusText; + }); + } + ctrl.loadDetails(); + } + + + /** + * TestAPI Modal instance Controller + * This controller is for the modal where a user can create + * test case or update the test case information. + */ + angular.module('testapiApp').controller('TestCaseModalCtrl', TestCaseModalCtrl); + TestCaseModalCtrl.$inject = ['$scope', '$uibModalInstance', 'data']; + function TestCaseModalCtrl($scope, $uibModalInstance, data) { + var ctrl = this; + ctrl.confirm = confirm; + ctrl.cancel = cancel; + ctrl.data = angular.copy(data); + + ctrl.createRequirements = [ + {label: 'name', type: 'text', required: true}, + {label: 'description', type: 'textarea', required: false}, + {label: 'version', type: 'text', required: false}, + {label: 'tier', type: 'text', required: false}, + {label: 'tags', type: 'text', required: false}, + {label: 'run', type: 'text', required: false}, + {label: 'dependencies', type: 'text', required: false}, + {label: 'trust', type: 'text', required: false}, + {label: 'url', type: 'text', required: false}, + {label: 'blocking', type: 'text', required: false}, + {label: 'criteria', type: 'text', required: false}, + {label: 'domains', type: 'text', required: false}, + {label: 'ci_loop', type: 'text', required: false}, + {label: 'catalog_description', type: 'text', required: false} + ]; + + ctrl.testcase = {name : null, description : null,version : null, tier : null, tags : null, + run : null, dependencies : null, trust : null, url : null, blocking : null, + criteria : null, domains : null, ci_loop: null, catalog_description : null}; + + if(ctrl.data.text=="Update"){ + ctrl.testcase = ctrl.data.testCase + delete ctrl.testcase._id; + ctrl.name = ctrl.data.testCase.name + } + + /** + * Initiate confirmation and call the success handler with the + * inputs. + */ + function confirm() { + $uibModalInstance.close(); + if (angular.isDefined(ctrl.data.successHandler)) { + ctrl.data.successHandler(ctrl.name, ctrl.testcase); + } + } + + /** + * Close the confirm modal without initiating changes. + */ + function cancel() { + $uibModalInstance.dismiss('cancel'); + } + } +})(); diff --git a/testapi/opnfv_testapi/ui/components/projects/project/updateModal.html b/testapi/opnfv_testapi/ui/components/projects/project/updateModal.html deleted file mode 100644 index ab8d64e..0000000 --- a/testapi/opnfv_testapi/ui/components/projects/project/updateModal.html +++ /dev/null @@ -1,26 +0,0 @@ -<div class="modal-header"><h3 class="modal-title">Confirm</h3></div> -<div class="modal-body"> - <div class="form-group"> - <h4>Update</h4> - <div class="row"> - <div ng-repeat="require in updateModal.createRequirements"> - <div class="update-project" style="margin-left:24px;"> - <p class="input-group"> - <label for="cpid">{{require.label|capitalize}}: </label> - <a ng-if="require.type == 'text'"> - <input type="text" dynamic-model="'updateModal.' + require.label"/> - </a> - <a ng-if="require.type == 'textarea'"> - <textarea rows="2" cols="50" value={{require.vaule}} dynamic-model="'updateModal.' + require.label"> - </textarea> - </a> - </p> - </div> - </div> - </div> - </div> -</div> -<div class="modal-footer"> - <button class="btn btn-primary" ng-click="updateModal.confirm()">Ok</button> - <button class="btn btn-default" ng-click="updateModal.cancel()">Cancel</button> -</div> diff --git a/testapi/opnfv_testapi/ui/components/projects/projects.html b/testapi/opnfv_testapi/ui/components/projects/projects.html index 28c08b1..b6b73d4 100644 --- a/testapi/opnfv_testapi/ui/components/projects/projects.html +++ b/testapi/opnfv_testapi/ui/components/projects/projects.html @@ -1,76 +1,69 @@ <h3>Projects</h3> <div class="row" style="margin-bottom:24px;"></div> -<div class="project-create" ng-class="{ 'hidden': ! ((auth.projectNames.length>0) && - auth.isAuthenticated) }"> - <h4>Create</h4> - <div class="row"> - <div ng-repeat="require in ctrl.createRequirements"> - <div class="create-project" style="margin-left:24px;"> - <p class="input-group"> - <label for="cpid">{{require.label|capitalize}}: </label> - <a ng-if="require.type == 'text'"> - <input type="text" dynamic-model="'ctrl.' + require.label"/> - </a> - <a ng-if="require.type == 'textarea'"> - <textarea rows="2" cols="50" dynamic-model="'ctrl.' + require.label"> - </textarea> - </a> - </p> - </div> - </div> - <div class="col-md-1 col-sm-1 col-xs-1 " style="margin-top:15px;"> - <button type="submit" class="btn btn-primary" ng-click="ctrl.create()">Create</button> - </div> - <div class="col-md-11 col-sm-11 col-xs-11"> - <div ng-show="ctrl.showCreateError" class="alert alert-danger" role="alert"> - <span class="glyphicon glyphicon-exclamation-sign" aria-hidden="true"></span> - <span class="sr-only">Error:</span> - {{ctrl.error}} - </div> - <div ng-show="ctrl.showCreateSuccess" class="alert alert-success" role="alert"> - <span class="glyphicon glyphicon-ok" aria-hidden="true"></span> - Create Success - </div> - </div> +<div class="row podsTable" style="vertical-align:middle"> + <div class="col-sm-1 pull-right" ng-class="{ 'hidden': !((auth.projectNames.length>0) && + auth.isAuthenticated) && authenticate}" > + <button type="button" class="btn btn-danger" ng-click="ctrl.openBatchDeleteModal()"> + <i class="fa fa-minus"></i> Delete</button> + </div> + <div class="col-sm-1 pull-right" ng-class="{ 'hidden': ! ((auth.projectNames.length>0) && + auth.isAuthenticated) && authenticate}"> + <button type="button" class="btn btn-success" ng-click="ctrl.openCreateModal()"> + <i class="fa fa-plus"></i> Create</button> + </div> + <div class="col-sm-1 pull-right"> + <button type="button" class="btn btn-success" ng-click="ctrl.listProjects()"> + <i class="fa fa-search"></i> Filter</button> + </div> + <div class="col-sm-3 pull-right"> + <span style="margin-top:6px">Search: </span> + <input type="text" class="form-control search" ng-Model="ctrl.filterText" style="width:80%;" placeholder="Search By Name"> </div> </div> - - -<div class="project-filters"> - <h4>Filters</h4> - <div class="row"> - <div class="col-md-3"> - <label for="cpid">Name</label> - <input type="text" class="form-control" - ng-model="ctrl.filterName"/> - </div> - <div class="col-md-1" style="margin-top:24px;"> - <button type="submit" class="btn btn-primary" ng-click="ctrl.update()">Filter</button> - </div> - <div class="col-md-1" style="margin-top:24px;"> - <button type="submit" class="btn btn-primary btn-danger" ng-click="ctrl.clearFilters()">Clear</button> - </div> - <div class="col-md-7" style="margin-top:10px;"> - <div ng-show="ctrl.showUpdateError" class="alert alert-danger" role="alert"> - <span class="glyphicon glyphicon-exclamation-sign" aria-hidden="true"></span> - <span class="sr-only">Error:</span> - {{ctrl.error}} - </div> - </div> +<div class='clo-md-12'> + <div ng-show="ctrl.showError" class="alert alert-danger" role="alert"> + <span class="pull-right"> {{ctrl.error}}</span> + <span class="glyphicon glyphicon-exclamation-sign pull-right" aria-hidden="true" >Error:</span> + </div> + <div ng-show="ctrl.showSuccess" class="alert alert-success" role="alert"> + <span class="pull-right"> {{ctrl.success}}</span> + <span class="glyphicon glyphicon-ok pull-right" aria-hidden="true"></span> </div> </div> - -<div ng-show="ctrl.data" class="projects-table" style="margin-top:24px; margin-left:8px;"> - <table ng-data="ctrl.data.projects" ng-show="ctrl.data" class="table table-striped table-hover"> +<div class='clo-md-12' style="padding-right:0px"> + <div class="table-responsive"> + <table class="table table-bordered table-hover" ng-data="ctrl.data.projects"> + <thead> + <tr style=" + text-align: center;"> + <th style="width: 1%;">Bulk Select</th> + <th style="width: 19%;">Name</th> + <th style="width: 70%;">Description</th> + <th style="width: 10%;" ng-class="{'hidden': ! ((auth.projectNames.length>0) && auth.isAuthenticated) && authenticate}">Operations</th> + </tr> + </thead> <tbody> - <tr ng-repeat-start="(index, project) in ctrl.data.projects"> - <td> - <a ui-sref='project({name: project.name})'>{{project.name}}</a> - </td> - </tr> - <tr ng-repeat-end=> - </tr> + <tr ng-repeat-start="(index, project) in ctrl.data.projects" style="padding:9px"> + <td> + <div class="text-center"> + <input type="checkbox" value="{{project.name}}" ng-model="ctrl.checkBox[index]" > + </div> + </td> + <td><a class="text-info" ng-click="ctrl.viewProject(project.name)">{{project.name}}</a></td> + <td>{{project.description}}</td> + <td ng-class="{'hidden': ! ((auth.projectNames.length>0) && auth.isAuthenticated) && authenticate}"> + <span class="podsTable-col"> + <a class="text-warning" ng-click="ctrl.openUpdateModal(project.name)" title="Edit" > + <i class="fa fa-pencil-square-o"></i></a> + <a class="text-danger" ng-click="ctrl.openDeleteModal(project.name)" title="Delete" > + <i class="fa fa-trash-o"></i></a> + </span> + </td> + </tr> + <tr ng-repeat-end=> + </tr> </tbody> - </table> + </table> + </div> </div>
\ No newline at end of file diff --git a/testapi/opnfv_testapi/ui/components/projects/projectsController.js b/testapi/opnfv_testapi/ui/components/projects/projectsController.js index 468407b..940c1e2 100644 --- a/testapi/opnfv_testapi/ui/components/projects/projectsController.js +++ b/testapi/opnfv_testapi/ui/components/projects/projectsController.js @@ -20,7 +20,8 @@ .controller('ProjectsController', ProjectsController); ProjectsController.$inject = [ - '$scope', '$http', '$filter', '$state', 'testapiApiUrl','raiseAlert' + '$scope', '$http', '$filter', '$state', '$window', '$uibModal', 'testapiApiUrl', + 'raiseAlert', 'confirmModal', 'authenticate' ]; /** @@ -28,80 +29,248 @@ * This controller is for the '/projects' page where a user can browse * through projects declared in TestAPI. */ - function ProjectsController($scope, $http, $filter, $state, testapiApiUrl, - raiseAlert) { + function ProjectsController($scope, $http, $filter, $state, $window, $uibModal, testapiApiUrl, + raiseAlert, confirmModal, authenticate) { var ctrl = this; ctrl.url = testapiApiUrl + '/projects'; + ctrl.create = create; + ctrl.listProjects = listProjects; + ctrl.openCreateModal = openCreateModal; + ctrl.viewProject = viewProject; + ctrl.openUpdateModal = openUpdateModal; ctrl.update = update; - ctrl.clearFilters = clearFilters; - - ctrl.createRequirements = [ - {label: 'name', type: 'text', required: true}, - {label: 'description', type: 'textarea', required: false} - ]; + ctrl.openDeleteModal = openDeleteModal; + ctrl.openBatchDeleteModal = openBatchDeleteModal; + ctrl.projectDelete = projectDelete; + ctrl.batchDelete = batchDelete; + ctrl.checkBox = []; + ctrl.checkBoxList = []; ctrl.name = ''; ctrl.details = ''; - ctrl.filterName=''; + ctrl.filterText=''; + /** * This will contact the TestAPI to create a new project. */ - function create() { - ctrl.showCreateError = false; - ctrl.showCreateSuccess = false; - if(ctrl.name != ""){ - var projects_url = ctrl.url; - var body = { - name: ctrl.name, - description: ctrl.description - }; - ctrl.projectsRequest = - $http.post(projects_url, body).success(function (data){ - ctrl.showCreateSuccess = true ; - ctrl.update(); - }).catch(function (data) { - ctrl.showCreateError = true; - ctrl.error = data.statusText; - }); - ctrl.name = ""; - ctrl.description=""; - } - else{ - ctrl.showCreateError = true; - ctrl.error = 'Name is missing.' + function create(project) { + ctrl.showError = false; + ctrl.showSuccess = false; + var projects_url = ctrl.url; + var body = { + name: project.name, + description: project.description + }; + ctrl.projectsRequest = + $http.post(projects_url, body).success(function (data){ + ctrl.showSuccess = true ; + ctrl.success = "Project is successfully created." + ctrl.listProjects(); + }).catch(function (data) { + ctrl.showError = true; + ctrl.error = data.statusText; + }); + } + + /** + * This will open the modal that will show the create + * project view + */ + function openCreateModal(){ + $uibModal.open({ + templateUrl: 'testapi-ui/components/projects/modals/projectModal.html', + controller: 'ProjectModalCtrl as ProjectModalCtrl', + size: 'md', + resolve: { + data: function () { + return { + text: "Create Project", + successHandler: ctrl.create + }; + } + } + }); + } + + /** + * This will open the modal that will show the update + * project view + */ + function openUpdateModal(name){ + var project; + var index; + for(index in ctrl.data.projects){ + if(ctrl.data.projects[index].name==name){ + project = ctrl.data.projects[index] + continue + } } + $uibModal.open({ + templateUrl: 'testapi-ui/components/projects/modals/projectModal.html', + controller: 'ProjectModalCtrl as ProjectModalCtrl', + size: 'md', + resolve: { + data: function () { + return { + text: "Update Project", + successHandler: ctrl.update, + project : project + }; + } + } + }); + } + + /** + * This will contact the TestAPI to update an existing test case. + */ + function update(name, project) { + ctrl.showError = false; + ctrl.showSuccess = false; + var projectUrl = ctrl.url + '/' + name; + ctrl.testCasesRequest = + $http.put(projectUrl, project).success(function (data){ + ctrl.showSuccess = true ; + ctrl.success = "Project is successfully updated." + listProjects(); + }) + .catch(function (data) { + ctrl.showError = true; + ctrl.error = data.statusText; + }); } /** * This will contact the TestAPI to get a listing of declared projects. */ - function update() { - ctrl.showUpdateError = false; + function listProjects() { + ctrl.showError = false; var content_url = ctrl.url + '?'; - var name = ctrl.filterName; - if(name){ + var filterText = ctrl.filterText; + if(filterText != ''){ content_url = content_url + 'name=' + - name; + filterText; } ctrl.resultsRequest = $http.get(content_url).success(function (data) { ctrl.data = data; }).catch(function (data) { ctrl.data = null; - ctrl.showUpdateError = true; + ctrl.showError = true; ctrl.error = data.statusText; }); } + function viewProject(name){ + $state.go('project', {'name':name}, {reload: true}); + } + + /** + * This will contact the TestAPI to delete a project for given + * name. + */ + function projectDelete(projectName){ + var projectUrl = ctrl.url + "/" + projectName + $http.delete(projectUrl).success(function(){ + ctrl.showSuccess = true ; + ctrl.success = "Projects is successfully deleted" + ctrl.listProjects(); + }).catch(function (data) { + ctrl.showError = true; + ctrl.showSuccess = false; + ctrl.error = data.statusText; + }); + } + /** - * This function will clear all filters and update the projects - * listing. + * This will delete list of projects. */ - function clearFilters() { - ctrl.filterName = null; - ctrl.showUpdateError = false; - ctrl.update(); + function batchDelete(){ + var index; + var checkedBox = []; + ctrl.checkBox.forEach(function(project, index){ + if(!ctrl.showError){ + if(project){ + projectDelete(ctrl.data.projects[index].name); + } + } + }); + ctrl.checkBox = [] + } + + /** + * This will open the modal that will show the batch delete confirm + * message + */ + function openBatchDeleteModal() { + confirmModal("Delete",ctrl.batchDelete); + } + + /** + * This will open the modal that will show the delete confirm + * message + */ + function openDeleteModal(name) { + confirmModal("Delete", ctrl.projectDelete, name); + } + + ctrl.listProjects(); + } + + /** + * TestAPI Project Modal Controller + * This controller is for the create modal where a user can create + * the project information and for the edit modal where user can + * edit the project's details + */ + angular.module('testapiApp').controller('ProjectModalCtrl', ProjectModalCtrl); + ProjectModalCtrl.$inject = ['$scope', '$uibModalInstance', 'data']; + function ProjectModalCtrl($scope, $uibModalInstance, data) { + var ctrl = this; + ctrl.confirm = confirm; + ctrl.cancel = cancel; + ctrl.data = angular.copy(data); + ctrl.createRequirements = [ + {label: 'name', type: 'text', required: true}, + {label: 'description', type: 'textarea', required: false} + ]; + ctrl.project = { + name : '', + description : '' + } + if(ctrl.data.project){ + ctrl.projectName = ctrl.data.project.name + ctrl.project = ctrl.data.project + delete ctrl.project._id; + } + + /** + * Initiate confirmation and call the success handler with the + * inputs. + */ + function confirm() { + if (angular.isDefined(ctrl.data.successHandler)) { + if(ctrl.project.name != ""){ + $uibModalInstance.close(); + if(ctrl.data.project){ + ctrl.data.successHandler(ctrl.projectName, ctrl.project); + }else{ + ctrl.data.successHandler(ctrl.project); + } + }else{ + ctrl.showCreateError = true; + ctrl.error = 'Name is missing.' + } + } + } + + /** + * Close the confirm modal without initiating changes. + */ + function cancel() { + $uibModalInstance.dismiss('cancel'); } } + })(); diff --git a/testapi/opnfv_testapi/ui/components/results/result/result.html b/testapi/opnfv_testapi/ui/components/results/result/result.html new file mode 100644 index 0000000..b435dce --- /dev/null +++ b/testapi/opnfv_testapi/ui/components/results/result/result.html @@ -0,0 +1,115 @@ +<legend>Result</legend> +<div style="padding-right:0px"> + <div class="table-responsive"> + <table class="table" ng-data="ctrl.data.pods"> + <tbody> + <tr style="padding:9px"> + <td class="podsTableTd">Id :</td> + <td class="podsTableLeftTd">{{ctrl.data._id}}</td> + </tr> + <tr style="padding:9px"> + <td class="podsTableTd">Pod Name:</td> + <td width="90%" class="podsTableLeftTd">{{ctrl.data.pod_name}}</td> + </tr> + <tr style="padding:9px"> + <td class="podsTableTd">Project Name:</td> + <td width="90%" class="podsTableLeftTd">{{ctrl.data.project_name}}</td> + </tr> + <tr style="padding:9px"> + <td class="podsTableTd">Case Name :</td> + <td width="90%" class="podsTableLeftTd">{{ctrl.data.case_name}}</td> + </tr> + <tr style="padding:9px"> + <td class="podsTableTd">Installer :</td> + <td width="90%" class="podsTableLeftTd">{{ctrl.data.installer}}</td> + </tr> + <tr style="padding:9px"> + <td class="podsTableTd">Version :</td> + <td width="90%" class="podsTableLeftTd">{{ctrl.data.version}}</td> + </tr> + <tr style="padding:9px"> + <td class="podsTableTd">Scenario :</td> + <td width="90%" class="podsTableLeftTd">{{ctrl.data.scenario}}</td> + </tr> + <tr style="padding:9px"> + <td class="podsTableTd">Build tag :</td> + <td width="90%" class="podsTableLeftTd">{{ctrl.data['build_tag']}}</td> + </tr> + <tr style="padding:9px"> + <td class="podsTableTd">Criteria :</td> + <td width="90%" class="podsTableLeftTd">{{ctrl.data.criteria}}</td> + </tr> + <tr style="padding:9px"> + <td class="podsTableTd">Start Date:</td> + <td width="90%" class="podsTableLeftTd">{{ctrl.data.start_date}}</td> + </tr> + <tr style="padding:9px"> + <td class="podsTableTd">Stop Date :</td> + <td width="90%" class="podsTableLeftTd">{{ctrl.data.stop_date}}</td> + </tr> + <tr style="padding:9px"> + <td class="podsTableTd">Trust Indicator :</td> + <td width="90%" class="podsTableLeftTd"> + <a ng-click="ctrl.showTrustIndicator()"> + <p ng-if="ctrl.trust_indicator">Hide</p> + <p ng-if="!ctrl.trust_indicator">Show</p> + </a> + <table class="table" ng-class="{'hidden' : !ctrl.trust_indicator}" style="margin:10px"> + <tbody> + <tr style="padding:9px"></tr> + <tr style="padding:9px" > + <td class="podsTableTd">Current :</td> + <td width="90%" class="podsTableLeftTd">{{ctrl.data.trust_indicator.current}}</td> + </tr> + <tr style="padding:9px" > + <td class="podsTableTd">Histories :</td> + <td width="90%" class="podsTableLeftTd">{{ctrl.data.trust_indicator.histories}}</td> + </tr> + </tbody> + </table> + </td> + </tr> + <tr style="padding:9px"> + <td class="podsTableTd">Details :</td> + <td width="90%" class="podsTableLeftTd"> + <a ng-click="ctrl.showDetails()"> + <p ng-if="ctrl.details">Hide</p> + <p ng-if="!ctrl.details">Show</p> + </a> + <table class="table" ng-class="{'hidden' : !ctrl.details}" style="margin:10px"> + <tbody> + <tr style="padding:9px"></tr> + <tr style="padding:9px"> + <td class="podsTableTd">Failures :</td> + <td width="90%" class="podsTableLeftTd">{{ctrl.data.details.failures}}</td> + </tr> + <tr style="padding:9px"> + <td class="podsTableTd">Details :</td> + <td width="90%" class="podsTableLeftTd">{{ctrl.data.details.errors}}</td> + </tr> + <tr style="padding:9px"> + <td class="podsTableTd">Stream :</td> + <td width="90%" class="podsTableLeftTd"><p>{{ctrl.data.details.stream}}</p></td> + </tr> + <tr style="padding:9px"> + <td class="podsTableTd">TestsRun :</td> + <td width="90%" class="podsTableLeftTd"><p>{{ctrl.data.details.testsRun}}</p></td> + </tr> + </tbody> + </table> + </td> + </tr> + </tbody> + </table> + </div> +</div> +<div class="col-md-12"> + <div ng-show="ctrl.showError" class="col-md-12 alert alert-danger" role="alert"> + <span class="pull-right"> {{ctrl.error}}</span> + <span class="glyphicon glyphicon-exclamation-sign pull-right" aria-hidden="true" >Error:</span> + </div> + <div ng-show="ctrl.showSuccess" class="col-md-12 alert alert-success" role="alert"> + <span class="pull-right"> {{ctrl.success}}</span> + <span class="glyphicon glyphicon-ok pull-right" aria-hidden="true"></span> + </div> + </div>
\ No newline at end of file diff --git a/testapi/opnfv_testapi/ui/components/results/result/resultController.js b/testapi/opnfv_testapi/ui/components/results/result/resultController.js new file mode 100644 index 0000000..028e5d8 --- /dev/null +++ b/testapi/opnfv_testapi/ui/components/results/result/resultController.js @@ -0,0 +1,74 @@ +/* + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +(function () { + 'use strict'; + + angular + .module('testapiApp') + .controller('ResultController', ResultController); + + ResultController.$inject = [ + '$scope', '$http', '$filter', '$state', '$window', '$uibModal', 'testapiApiUrl','raiseAlert', + 'confirmModal' + ]; + + /** + * TestAPI ResultController + * This controller is for the '/result/:_id' page where a user can browse + * through result declared in TestAPI. + */ + function ResultController($scope, $http, $filter, $state, $window, $uibModal, testapiApiUrl, + raiseAlert, confirmModal) { + var ctrl = this; + ctrl.url = testapiApiUrl + '/results'; + ctrl._id = $state.params['_id']; + ctrl.loadDetails = loadDetails + ctrl.showTrustIndicator = showTrustIndicator + ctrl.showDetails = showDetails + + /** + *Contact the testapi and retrevie the result details + */ + function loadDetails(){ + var resultUrl = ctrl.url + '/' + ctrl._id; + ctrl.showError = false; + ctrl.podsRequest = + $http.get(resultUrl).success(function (data) { + ctrl.data = data; + }).catch(function (error) { + ctrl.data = null; + ctrl.showError = true; + ctrl.error = error.statusText; + }); + } + + function showTrustIndicator(){ + if(ctrl.trust_indicator){ + ctrl.trust_indicator = false + }else{ + ctrl.trust_indicator = true + } + } + + function showDetails(){ + if(ctrl.details){ + ctrl.details = false + }else{ + ctrl.details = true + } + } + ctrl.loadDetails(); + } +})();
\ No newline at end of file diff --git a/testapi/opnfv_testapi/ui/components/results/results.html b/testapi/opnfv_testapi/ui/components/results/results.html index 2ae5339..b0c05ba 100644 --- a/testapi/opnfv_testapi/ui/components/results/results.html +++ b/testapi/opnfv_testapi/ui/components/results/results.html @@ -18,15 +18,28 @@ </div> </form> <div class="row" style="margin-bottom:24px;"></div> -<div class="result-filters"> - <h4>Filters</h4> - <div class="row"> - <div class="col-md-3"> - <label for="cpid">Start Date</label> - <p class="input-group"> +<div class="result-filters" style="border-top: none;"> + <div class="row podTable" style="vertical-align:middle"> + <div class="col-sm-1 pull-right"> + <button type="button" class="btn btn-danger" ng-click="ctrl.clearFilters()"> + <i class="fa fa-search"></i> Clear + </button> + </div> + <div class="col-sm-1 pull-right"> + <button type="button" class="btn btn-success" ng-click="ctrl.filterList()"> + <i class="fa fa-search"></i> Filter</button> + </div> + <div class="col-sm-2 pull-right" ng-class="{'hidden': ctrl.filter=='start_date' || ctrl.filter=='end_date'}"> + <span style="margin-top:6px">Search: </span> + <input type="text" class="form-control search" style="display:inline;width:105px;padding-left:6px;" + ng-Model="ctrl.filterText" placeholder="Search String"> + </div> + <div class="col-sm-3 pull-right" style="width:20%" ng-class="{'hidden': ctrl.filter!='start_date'}"> + <span style="margin-top:6px">Start Date: </span> + <p class="input-group" style="width:48%;display:inline-flex;"> <input type="text" class="form-control" uib-datepicker-popup="{{ctrl.format}}" - ng-model="ctrl.startDate" is-open="ctrl.startOpen" + ng-model="ctrl.filterText" is-open="ctrl.startOpen" close-text="Close" /> <span class="input-group-btn"> <button type="button" class="btn btn-default" ng-click="ctrl.open($event, 'startOpen')"> @@ -35,12 +48,12 @@ </span> </p> </div> - <div class="col-md-3"> - <label for="cpid">End Date</label> - <p class="input-group"> + <div class="col-sm-3 pull-right" style="width:20%" ng-class="{'hidden': ctrl.filter!='end_date'}"> + <span style="margin-top:6px">End Date: </span> + <p class="input-group" style="width:48%;display:inline-flex;"> <input type="text" class="form-control" uib-datepicker-popup="{{ctrl.format}}" - ng-model="ctrl.endDate" is-open="ctrl.endOpen" + ng-model="ctrl.filterText" is-open="ctrl.endOpen" close-text="Close" /> <span class="input-group-btn"> <button type="button" class="btn btn-default" ng-click="ctrl.open($event, 'endOpen')"> @@ -49,9 +62,29 @@ </span> </p> </div> - <div class="col-md-3" style="margin-top:24px;"> - <button type="submit" class="btn btn-primary" ng-click="ctrl.update()">Filter</button> - <button type="submit" class="btn btn-primary btn-danger" ng-click="ctrl.clearFilters()">Clear</button> + <div class="col-md-2 row pull-right" style="width: 20%;"> + <span style="margin-top:6px">Filter: </span> + <select ng-model="ctrl.filter" class="form-control" style="display:inline; width:150px;"> + <option value="pod" ng-disabled="ctrl.testFilter('pod')" >Pod Name</option> + <option value="project" ng-disabled="ctrl.testFilter('project')" >Project Name</option> + <option value="case" ng-disabled="ctrl.testFilter('case')">Case Name</option> + <option value="installer" ng-disabled="ctrl.testFilter('installer')">Installer</option> + <option value="version" ng-disabled="ctrl.testFilter('version')">Version</option> + <option value="scenario" ng-disabled="ctrl.testFilter('scenario')">Scenario</option> + <option value="build_tag" ng-disabled="ctrl.testFilter('build_tag')">Build Tag</option> + <option value="criteria" ng-disabled="ctrl.testFilter('criteria')">Criteria</option> + <option value="start_date" ng-disabled="ctrl.testFilter('start_date')">Start Date</option> + <option value="end_date" ng-disabled="ctrl.testFilter('end_date')">End Date</option> + </select> + </div> + + <div class='filter-box'> + <div class='filter-tag' ng-repeat="(key, tag) in ctrl.tagArray"> + {{key}} : {{tag}} + <div class='delete-tag' ng-click='ctrl.deleteTag(key)'> + × + </div> + </div> </div> </div> </div> @@ -70,14 +103,13 @@ <th>Version</th> <th>Scenario</th> <th>Criteria</th> - <th>Start Date</th> - <th>Stop Date</th> + <th>Build tag</th> </tr> </thead> <tbody> <tr ng-repeat-start="(index, result) in ctrl.data.results"> - <td>{{ result._id }}</td> + <td><a ng-click="ctrl.viewResult(result._id)">{{ result._id.substr(-8) }}</a></td> <td>{{ result.pod_name }}</td> <td>{{ result.project_name }}</td> <td>{{ result.case_name }}</td> @@ -85,8 +117,7 @@ <td>{{ result.version }}</td> <td>{{ result.scenario }}</td> <td>{{ result.criteria }}</td> - <td>{{ result.start_date }}</td> - <td>{{ result.stop_date }}</td> + <td>{{ result["build_tag"]}}</td> </tr> <tr ng-repeat-end=> </tr> @@ -103,7 +134,7 @@ boundary-links="true" rotate="false" num-pages="ctrl.numPages" - ng-change="ctrl.update()"> + ng-change="ctrl.filterList()"> </uib-pagination> </div> </div> diff --git a/testapi/opnfv_testapi/ui/components/results/resultsController.js b/testapi/opnfv_testapi/ui/components/results/resultsController.js index cc6cc0b..73f3c15 100644 --- a/testapi/opnfv_testapi/ui/components/results/resultsController.js +++ b/testapi/opnfv_testapi/ui/components/results/resultsController.js @@ -50,16 +50,14 @@ raiseAlert) { var ctrl = this; - ctrl.uploadFile=uploadFile; - ctrl.update = update; ctrl.open = open; ctrl.clearFilters = clearFilters; - ctrl.associateMeta = associateMeta; - ctrl.getVersionList = getVersionList; - ctrl.getUserProducts = getUserProducts; - ctrl.associateProductVersion = associateProductVersion; - ctrl.getProductVersions = getProductVersions; - ctrl.prepVersionEdit = prepVersionEdit; + ctrl.deleteTag = deleteTag; + ctrl.filterList= filterList; + ctrl.testFilter = testFilter + ctrl.viewResult = viewResult; + + ctrl.tagArray = {} /** Mappings of Interop WG components to marketing program names. */ ctrl.targetMappings = { @@ -97,99 +95,98 @@ /** Check to see if this page should display user-specific results. */ // ctrl.isUserResults = $state.current.name === 'userResults'; // need auth to browse - ctrl.isUserResults = $state.current.name === 'userResults'; + // ctrl.isUserResults = $state.current.name === 'userResults'; - // Should only be on user-results-page if authenticated. - if (ctrl.isUserResults && !$scope.auth.isAuthenticated) { - $state.go('home'); - } + // // Should only be on user-results-page if authenticated. + // if (ctrl.isUserResults && !$scope.auth.isAuthenticated) { + // $state.go('home'); + // } - ctrl.pageHeader = ctrl.isUserResults ? - 'Private test results' : 'Community test results'; + ctrl.pageHeader = "Test Results" ctrl.pageParagraph = ctrl.isUserResults ? 'Your most recently uploaded test results are listed here.' : 'The most recently uploaded community test results are listed ' + 'here.'; - ctrl.uploadState = ''; + // ctrl.uploadState = ''; ctrl.isPublic = false; - if (ctrl.isUserResults) { - ctrl.authRequest = $scope.auth.doSignCheck() - .then(ctrl.update); - // ctrl.getUserProducts(); - } else { - ctrl.update(); - } - - - function uploadFileToUrl(file, uploadUrl){ - var fd = new FormData(); - fd.append('file', file); - fd.append('public', ctrl.isPublic) - - $http.post(uploadUrl, fd, { - transformRequest: angular.identity, - headers: {'Content-Type': undefined} - }) - - .success(function(data){ - var id = data.href.substr(data.href.lastIndexOf('/')+1); - ctrl.uploadState = "Upload succeed. Result id is " + id; - ctrl.update(); - }) + // if (ctrl.isUserResults) { + // ctrl.authRequest = $scope.auth.doSignCheck() + // .then(ctrl.filterList); + // // ctrl.getUserProducts(); + // } else { + // ctrl.filterList(); + // } - .error(function(data, status){ - ctrl.uploadState = "Upload failed. Error code is " + status; - }); + function viewResult(_id){ + $state.go('result', {'_id':_id}, {reload: true}); } - function uploadFile(){ - var file = $scope.resultFile; - console.log('file is ' ); - console.dir(file); + function deleteTag(index){ + delete ctrl.tagArray[index]; + ctrl.filterList(); + } - var uploadUrl = testapiApiUrl + "/results/upload"; - uploadFileToUrl(file, uploadUrl); - }; + function testFilter(text){ + for (var filter in ctrl.tagArray){ + if(text==filter){ + return true; + } + } + return false; + } /** * This will contact the TestAPI API to get a listing of test run * results. */ - function update() { + function filterList(){ + if(ctrl.filter && ctrl.filterText!=""){ + ctrl.tagArray[ctrl.filter] = ctrl.filterText; + } ctrl.showError = false; - // Construct the API URL based on user-specified filters. var content_url = testapiApiUrl + '/results' + '?page=' + ctrl.currentPage; - var start = $filter('date')(ctrl.startDate, 'yyyy-MM-dd'); - if (start) { - content_url = - content_url + '&from=' + start + ' 00:00:00'; - } - var end = $filter('date')(ctrl.endDate, 'yyyy-MM-dd'); - if (end) { - content_url = content_url + '&to=' + end + ' 23:59:59'; - } - if (ctrl.isUserResults) { - content_url = content_url + '&signed'; + for(var key in ctrl.tagArray){ + if(key=="start_date"){ + var start = $filter('date')(ctrl.tagArray[key], 'yyyy-MM-dd'); + if (start) { + content_url = + content_url + '&from=' + start + ' 00:00:00'; + } + } + else if(key=="end_date"){ + var end = $filter('date')(ctrl.tagArray[key], 'yyyy-MM-dd'); + if (end) { + content_url = content_url + '&to=' + end + ' 23:59:59'; + } + } + else{ + content_url = content_url + "&" + key + "=" + ctrl.tagArray[key] + } + if (ctrl.isUserResults) { + content_url = content_url + '&signed'; + } } ctrl.resultsRequest = - $http.get(content_url).success(function (data) { - ctrl.data = data; - ctrl.totalItems = ctrl.data.pagination.total_pages * ctrl.itemsPerPage; - ctrl.currentPage = ctrl.data.pagination.current_page; - }).error(function (error) { - ctrl.data = null; - ctrl.totalItems = 0; - ctrl.showError = true; - ctrl.error = - 'Error retrieving results listing from server: ' + - angular.toJson(error); - }); + $http.get(content_url).success(function (data) { + ctrl.data = data; + ctrl.totalItems = ctrl.data.pagination.total_pages * ctrl.itemsPerPage; + ctrl.currentPage = ctrl.data.pagination.current_page; + }).error(function (error) { + ctrl.data = null; + ctrl.totalItems = 0; + ctrl.showError = true; + ctrl.error = + 'Error retrieving results listing from server: ' + + angular.toJson(error); + }); + ctrl.filterText = '' } + ctrl.filterList(); /** * This is called when the date filter calendar is opened. It @@ -209,162 +206,9 @@ * listing. */ function clearFilters() { - ctrl.startDate = null; - ctrl.endDate = null; - ctrl.update(); - } - - /** - * This will send an API request in order to associate a metadata - * key-value pair with the given testId - * @param {Number} index - index of the test object in the results list - * @param {String} key - metadata key - * @param {String} value - metadata value - */ - function associateMeta(index, key, value) { - var testId = ctrl.data.results[index].id; - var metaUrl = [ - testapiApiUrl, '/results/', testId, '/meta/', key - ].join(''); - - var editFlag = key + 'Edit'; - if (value) { - ctrl.associateRequest = $http.post(metaUrl, value) - .success(function () { - ctrl.data.results[index][editFlag] = false; - }).error(function (error) { - raiseAlert('danger', error.title, error.detail); - }); - } - else { - ctrl.unassociateRequest = $http.delete(metaUrl) - .success(function () { - ctrl.data.results[index][editFlag] = false; - }).error(function (error) { - if (error.code == 404) { - // Key doesn't exist, so count it as a success, - // and don't raise an alert. - ctrl.data.results[index][editFlag] = false; - } - else { - raiseAlert('danger', error.title, error.detail); - } - }); - } + ctrl.tagArray = {} + ctrl.filter = undefined + ctrl.filterList(); } - - /** - * Retrieve an array of available capability files from the TestAPI - * API server, sort this array reverse-alphabetically, and store it in - * a scoped variable. - * Sample API return array: ["2015.03.json", "2015.04.json"] - */ - function getVersionList() { - if (ctrl.versionList) { - return; - } - var content_url = testapiApiUrl + '/guidelines'; - ctrl.versionsRequest = - $http.get(content_url).success(function (data) { - ctrl.versionList = data.sort().reverse(); - }).error(function (error) { - raiseAlert('danger', error.title, - 'Unable to retrieve version list'); - }); - } - - /** - * Get products user has management rights to or all products depending - * on the passed in parameter value. - */ - function getUserProducts() { - if (ctrl.products) { - return; - } - var contentUrl = testapiApiUrl + '/products'; - ctrl.productsRequest = - $http.get(contentUrl).success(function (data) { - ctrl.products = {}; - angular.forEach(data.products, function(prod) { - if (prod.can_manage) { - ctrl.products[prod.id] = prod; - } - }); - }).error(function (error) { - ctrl.products = null; - ctrl.showError = true; - ctrl.error = - 'Error retrieving Products listing from server: ' + - angular.toJson(error); - }); - } - - /** - * Send a PUT request to the API server to associate a product with - * a test result. - */ - function associateProductVersion(result) { - var verId = (result.selectedVersion ? - result.selectedVersion.id : null); - var testId = result.id; - var url = testapiApiUrl + '/results/' + testId; - ctrl.associateRequest = $http.put(url, {'product_version_id': - verId}) - .success(function (data) { - result.product_version = result.selectedVersion; - if (result.selectedVersion) { - result.product_version.product_info = - result.selectedProduct; - } - result.productEdit = false; - }).error(function (error) { - raiseAlert('danger', error.title, error.detail); - }); - } - - /** - * Get all versions for a product. - */ - function getProductVersions(result) { - if (!result.selectedProduct) { - result.productVersions = []; - result.selectedVersion = null; - return; - } - - var url = testapiApiUrl + '/products/' + - result.selectedProduct.id + '/versions'; - ctrl.getVersionsRequest = $http.get(url) - .success(function (data) { - result.productVersions = data; - - // If the test result isn't already associated to a - // version, default it to the null version. - if (!result.product_version) { - angular.forEach(data, function(ver) { - if (!ver.version) { - result.selectedVersion = ver; - } - }); - } - }).error(function (error) { - raiseAlert('danger', error.title, error.detail); - }); - } - - /** - * Instantiate variables needed for editing product/version - * associations. - */ - function prepVersionEdit(result) { - result.productEdit = true; - if (result.product_version) { - result.selectedProduct = - ctrl.products[result.product_version.product_info.id]; - } - result.selectedVersion = result.product_version; - ctrl.getProductVersions(result); - } - } })(); diff --git a/testapi/opnfv_testapi/ui/components/scenarios/modals/customModal.html b/testapi/opnfv_testapi/ui/components/scenarios/modals/customModal.html new file mode 100644 index 0000000..987cb1e --- /dev/null +++ b/testapi/opnfv_testapi/ui/components/scenarios/modals/customModal.html @@ -0,0 +1,28 @@ +<div class="ball" style="padding:5px;"> + <div class="modal-body"> + <div class="form-horizontal"> + <fieldset> + <div class="form-group"> + <legend>{{customModalCtrl.data.text}}</legend> + <div class="row"> + <div class="update-project"> + <label for="cpid" class="control-label col-sm-4">Custom: </label> + <div class="col-sm-6"> + <input type="text" class="form-control" ng-model="customModalCtrl.custom"/> + <p class="help-block"></p> + </div> + </div> + </div> + </div> + </fieldset> + </div> + </div> + <div class="modal-footer"> + <div ng-show="customModalCtrl.showCreateError" style="padding:0px;" class="col-md-6 alert alert-danger" role="alert"> + <span class="pull-right"> {{customModalCtrl.error}}</span> + <span class="glyphicon glyphicon-exclamation-sign pull-right" aria-hidden="true" >Error:</span> + </div> + <button class="btn btn-primary" ng-click="customModalCtrl.confirm()">Ok</button> + <button class="btn btn-default" ng-click="customModalCtrl.cancel()">Cancel</button> + </div> + </div>
\ No newline at end of file diff --git a/testapi/opnfv_testapi/ui/components/scenarios/modals/installerModal.html b/testapi/opnfv_testapi/ui/components/scenarios/modals/installerModal.html new file mode 100644 index 0000000..4be1375 --- /dev/null +++ b/testapi/opnfv_testapi/ui/components/scenarios/modals/installerModal.html @@ -0,0 +1,59 @@ +<div class="ball" style="padding:5px;"> + <div class="modal-body"> + <div class="form-horizontal"> + <fieldset> + <div class="form-group"> + <legend>{{installerModalCtrl.data.text}}</legend> + <div class="row"> + <div class="update-project"> + <div class="col-sm-4"> + <label for="cpid" class="control-label col-sm-2"> Name: </label> + </div> + <div class="col-sm-6"> + <input type="text" class="form-control" ng-model="installerModalCtrl.installer.installer"/> + <p class="help-block"></p> + </div> + </div> + <div class="update-project"> + <div class="col-sm-4"> + <label for="cpid" class="control-label col-sm-2"> Version: </label> + </div> + <div class="col-sm-6"> + <button class="btn btn-primary" ng-click="installerModalCtrl.openVersionModal()">Add Version</button> + <p class="help-block"></p> + </div> + </div> + </div> + </div> + </fieldset> + </div> + <div class='clo-md-12' style="padding-right:0px"> + <h3>Version</h3> + <div class="table-responsive"> + <table class="table table-bordered table-hover" ng-data="installerModalCtrl.installer.versions"> + <thead> + <tr style=" + text-align: center;"> + <th style="width: 19%;">Version</th> + </tr> + </thead> + <tbody> + <tr ng-repeat-start="(index, version) in installerModalCtrl.installer.versions" style="padding:9px"> + <td>{{version.version}}</td> + </tr> + <tr ng-repeat-end=> + </tr> + </tbody> + </table> + </div> + </div> + </div> + <div class="modal-footer"> + <div ng-show="installerModalCtrl.showCreateError" style="padding:0px;" class="col-md-6 alert alert-danger" role="alert"> + <span class="pull-right"> {{installerModalCtrl.error}}</span> + <span class="glyphicon glyphicon-exclamation-sign pull-right" aria-hidden="true" >Error:</span> + </div> + <button class="btn btn-primary" ng-click="installerModalCtrl.confirm()">Ok</button> + <button class="btn btn-default" ng-click="installerModalCtrl.cancel()">Cancel</button> + </div> + </div>
\ No newline at end of file diff --git a/testapi/opnfv_testapi/ui/components/scenarios/modals/projectModal.html b/testapi/opnfv_testapi/ui/components/scenarios/modals/projectModal.html new file mode 100644 index 0000000..0a14be9 --- /dev/null +++ b/testapi/opnfv_testapi/ui/components/scenarios/modals/projectModal.html @@ -0,0 +1,59 @@ +<div class="ball" style="padding:5px;"> + <div class="modal-body"> + <div class="form-horizontal"> + <fieldset> + <div class="form-group"> + <legend>{{projectModalCtrl.data.text}}</legend> + <div class="row"> + <div class="update-project"> + <div class="col-sm-4"> + <label for="cpid" class="control-label"> Project Name: </label> + </div> + <div class="col-sm-6"> + <input type="text" class="form-control" ng-model="projectModalCtrl.project.project"/> + <p class="help-block"></p> + </div> + </div> + <div class="update-project"> + <div class="col-sm-4"> + <label for="cpid" class="control-label"> Custom: </label> + </div> + <div class="col-sm-6"> + <button class="btn btn-primary" ng-click="projectModalCtrl.openCustomModal()">Add Custom</button> + <p class="help-block"></p> + </div> + </div> + </div> + </div> + </fieldset> + </div> + <div class='clo-md-12' style="padding-right:0px"> + <h3>Customs</h3> + <div class="table-responsive"> + <table class="table table-bordered table-hover" ng-data="projectModalCtrl.project.customs"> + <thead> + <tr style=" + text-align: center;"> + <th style="width: 1%;">Custom</th> + </tr> + </thead> + <tbody> + <tr ng-repeat-start="(index, custom) in projectModalCtrl.project.customs" style="padding:9px"> + <td>{{custom}}</td> + </tr> + <tr ng-repeat-end=> + </tr> + </tbody> + </table> + </div> + </div> + </div> + <div class="modal-footer"> + <div ng-show="projectModalCtrl.showCreateError" style="padding:0px;" class="col-md-6 alert alert-danger" role="alert"> + <span class="pull-right"> {{projectModalCtrl.error}}</span> + <span class="glyphicon glyphicon-exclamation-sign pull-right" aria-hidden="true" >Error:</span> + </div> + <button class="btn btn-primary" ng-click="projectModalCtrl.confirm()">Ok</button> + <button class="btn btn-default" ng-click="projectModalCtrl.cancel()">Cancel</button> + </div> + </div>
\ No newline at end of file diff --git a/testapi/opnfv_testapi/ui/components/scenarios/modals/scenarioModal.html b/testapi/opnfv_testapi/ui/components/scenarios/modals/scenarioModal.html new file mode 100644 index 0000000..2b5ba9e --- /dev/null +++ b/testapi/opnfv_testapi/ui/components/scenarios/modals/scenarioModal.html @@ -0,0 +1,59 @@ +<div class="ball" style="padding:5px;"> + <div class="modal-body"> + <div class="form-horizontal"> + <fieldset> + <div class="form-group"> + <legend>{{scenarioModalController.data.text}}</legend> + <div class="row"> + <div class="update-project"> + <div class="col-sm-4"> + <label for="cpid" class="control-label col-sm-2"> Name: </label> + </div> + <div class="col-sm-6"> + <input type="text" class="form-control" ng-model="scenarioModalController.scenario.name"/> + <p class="help-block"></p> + </div> + </div> + <div class="update-project"> + <div class="col-sm-4"> + <label for="cpid" class="control-label col-sm-2"> Installer: </label> + </div> + <div class="col-sm-6"> + <button class="btn btn-primary" ng-click="scenarioModalController.openInstallerModal()">Add Installer</button> + <p class="help-block"></p> + </div> + </div> + </div> + </div> + </fieldset> + </div> + <div class='clo-md-12' style="padding-right:0px"> + <h3>Installers</h3> + <div class="table-responsive"> + <table class="table table-bordered table-hover" ng-data="scenarioModalController.scenario"> + <thead> + <tr style=" + text-align: center;"> + <th style="width: 19%;">Installers</th> + </tr> + </thead> + <tbody> + <tr ng-repeat-start="(index, installer) in scenarioModalController.scenario.installers" style="padding:9px"> + <td>{{installer.installer}}</td> + </tr> + <tr ng-repeat-end=> + </tr> + </tbody> + </table> + </div> + </div> + </div> + <div class="modal-footer"> + <div ng-show="scenarioModalController.showCreateError" style="padding:0px;" class="col-md-6 alert alert-danger" role="alert"> + <span class="pull-right"> {{scenarioModalController.error}}</span> + <span class="glyphicon glyphicon-exclamation-sign pull-right" aria-hidden="true" >Error:</span> + </div> + <button class="btn btn-primary" ng-click="scenarioModalController.confirm()">Ok</button> + <button class="btn btn-default" ng-click="scenarioModalController.cancel()">Cancel</button> + </div> +</div>
\ No newline at end of file diff --git a/testapi/opnfv_testapi/ui/components/scenarios/modals/scenarioNameUpdate.html b/testapi/opnfv_testapi/ui/components/scenarios/modals/scenarioNameUpdate.html new file mode 100644 index 0000000..e793c05 --- /dev/null +++ b/testapi/opnfv_testapi/ui/components/scenarios/modals/scenarioNameUpdate.html @@ -0,0 +1,28 @@ +<div class="ball" style="padding:5px;"> + <div class="modal-body"> + <div class="form-horizontal"> + <fieldset> + <div class="form-group"> + <legend>{{ScenarioNameUpdateCtrl.data.text}}</legend> + <div class="row"> + <div class="update-project"> + <label for="cpid" class="control-label col-sm-4">Name: </label> + <div class="col-sm-6"> + <input type="text" class="form-control" ng-model="ScenarioNameUpdateCtrl.name"/> + <p class="help-block"></p> + </div> + </div> + </div> + </div> + </fieldset> + </div> + </div> + <div class="modal-footer"> + <div ng-show="ScenarioNameUpdateCtrl.showCreateError" style="padding:0px;" class="col-md-6 alert alert-danger" role="alert"> + <span class="pull-right"> {{ScenarioNameUpdateCtrl.error}}</span> + <span class="glyphicon glyphicon-exclamation-sign pull-right" aria-hidden="true" >Error:</span> + </div> + <button class="btn btn-primary" ng-click="ScenarioNameUpdateCtrl.confirm()">Ok</button> + <button class="btn btn-default" ng-click="ScenarioNameUpdateCtrl.cancel()">Cancel</button> + </div> + </div>
\ No newline at end of file diff --git a/testapi/opnfv_testapi/ui/components/scenarios/modals/scoreModal.html b/testapi/opnfv_testapi/ui/components/scenarios/modals/scoreModal.html new file mode 100644 index 0000000..55b5cfd --- /dev/null +++ b/testapi/opnfv_testapi/ui/components/scenarios/modals/scoreModal.html @@ -0,0 +1,51 @@ + + + <div class="ball" style="padding:5px;"> + <div class="modal-body"> + <div class="form-horizontal"> + <fieldset> + <div class="form-group"> + <legend>{{scoreModalCtrl.data.text}}</legend> + <div class="row"> + <div class="update-project"> + <label for="cpid" class="control-label col-sm-4">Score: </label> + <div class="col-sm-6"> + <input type="text" class="form-control" ng-model="scoreModalCtrl.score.score"/> + <p class="help-block"></p> + </div> + </div> + <div class="update-project"> + <div> + <div class="col-md-4" style="text-align:right;"> + <span style="margin-top:6px;">Date: </span> + </div> + <div class="col-md-6"> + <p class="input-group" style="display:inline-flex;"> + <input type="text" class="form-control" + uib-datepicker-popup="{{scoreModalCtrl.format}}" + ng-model="scoreModalCtrl.score.date" is-open="scoreModalCtrl.endOpen" + close-text="Close" /> + <span class="input-group-btn"> + <button type="button" class="btn btn-default" ng-click="scoreModalCtrl.open($event, 'endOpen')"> + <i class="glyphicon glyphicon-calendar"></i> + </button> + </span> + </p> + </div> + </div> + </div> + </div> + </div> + </div> + </fieldset> + </div> + </div> + <div class="modal-footer"> + <div ng-show="scoreModalCtrl.showCreateError" style="padding:0px;" class="col-md-6 alert alert-danger" role="alert"> + <span class="pull-right"> {{scoreModalCtrl.error}}</span> + <span class="glyphicon glyphicon-exclamation-sign pull-right" aria-hidden="true" >Error:</span> + </div> + <button class="btn btn-primary" ng-click="scoreModalCtrl.confirm()">Ok</button> + <button class="btn btn-default" ng-click="scoreModalCtrl.cancel()">Cancel</button> + </div> + </div>
\ No newline at end of file diff --git a/testapi/opnfv_testapi/ui/components/scenarios/modals/trustIndicatorModal.html b/testapi/opnfv_testapi/ui/components/scenarios/modals/trustIndicatorModal.html new file mode 100644 index 0000000..b84bd5d --- /dev/null +++ b/testapi/opnfv_testapi/ui/components/scenarios/modals/trustIndicatorModal.html @@ -0,0 +1,49 @@ +<div class="ball" style="padding:5px;"> + <div class="modal-body"> + <div class="form-horizontal"> + <fieldset> + <div class="form-group"> + <legend>{{trustIndicatorModalCtrl.data.text}}</legend> + <div class="row"> + <div class="update-project"> + <label for="cpid" class="control-label col-sm-4">Status: </label> + <div class="col-sm-6"> + <input type="text" class="form-control" ng-model="trustIndicatorModalCtrl.ti.status"/> + <p class="help-block"></p> + </div> + </div> + <div class="update-project"> + <div> + <div class="col-md-4" style="text-align:right;"> + <span style="margin-top:6px;">Date: </span> + </div> + <div class="col-md-6"> + <p class="input-group" style="display:inline-flex;"> + <input type="text" class="form-control" + uib-datepicker-popup="{{trustIndicatorModalCtrl.format}}" + ng-model="trustIndicatorModalCtrl.ti.date" is-open="trustIndicatorModalCtrl.endOpen" + close-text="Close" /> + <span class="input-group-btn"> + <button type="button" class="btn btn-default" ng-click="trustIndicatorModalCtrl.open($event, 'endOpen')"> + <i class="glyphicon glyphicon-calendar"></i> + </button> + </span> + </p> + </div> + </div> + </div> + </div> + </div> + </div> + </fieldset> + </div> + </div> + <div class="modal-footer"> + <div ng-show="trustIndicatorModalCtrl.showCreateError" style="padding:0px;" class="col-md-6 alert alert-danger" role="alert"> + <span class="pull-right"> {{trustIndicatorModalCtrl.error}}</span> + <span class="glyphicon glyphicon-exclamation-sign pull-right" aria-hidden="true" >Error:</span> + </div> + <button class="btn btn-primary" ng-click="trustIndicatorModalCtrl.confirm()">Ok</button> + <button class="btn btn-default" ng-click="trustIndicatorModalCtrl.cancel()">Cancel</button> + </div> + </div>
\ No newline at end of file diff --git a/testapi/opnfv_testapi/ui/components/scenarios/modals/versionModal.html b/testapi/opnfv_testapi/ui/components/scenarios/modals/versionModal.html new file mode 100644 index 0000000..f679f0b --- /dev/null +++ b/testapi/opnfv_testapi/ui/components/scenarios/modals/versionModal.html @@ -0,0 +1,68 @@ +<div class="ball" style="padding:5px;"> + <div class="modal-body"> + <div class="form-horizontal"> + <fieldset> + <div class="form-group"> + <legend>{{versionModalCtrl.data.text}}</legend> + <div class="row"> + <div class="update-project"> + <div class="col-sm-4"> + <label for="cpid" class="control-label col-sm-2"> Version: </label> + </div> + <div class="col-sm-6"> + <input type="text" class="form-control" ng-model="versionModalCtrl.version.version"/> + <p class="help-block"></p> + </div> + </div> + <div class="update-project"> + <div class="col-sm-4"> + <label for="cpid" class="control-label col-sm-2"> Owner: </label> + </div> + <div class="col-sm-6"> + <input type="text" class="form-control" ng-model="versionModalCtrl.version.owner"/> + <p class="help-block"></p> + </div> + </div> + <div class="update-project"> + <div class="col-sm-4"> + <label for="cpid" class="control-label col-sm-2"> Project: </label> + </div> + <div class="col-sm-4"> + <button class="btn btn-primary" ng-click="versionModalCtrl.openProjectModal()">Add Project:</button> + <p class="help-block"></p> + </div> + </div> + </div> + </div> + </fieldset> + </div> + <div class='clo-md-12' style="padding-right:0px"> + <h3>Projects</h3> + <div class="table-responsive"> + <table class="table table-bordered table-hover" ng-data="versionModalCtrl.version.projects"> + <thead> + <tr style=" + text-align: center;"> + <th style="width: 19%;">Project</th> + </tr> + </thead> + <tbody> + <tr ng-repeat-start="(index, project) in versionModalCtrl.version.projects" style="padding:9px"> + <td>{{project.project}}</td> + </tr> + <tr ng-repeat-end=> + </tr> + </tbody> + </table> + </div> + </div> + </div> + <div class="modal-footer"> + <div ng-show="versionModalCtrl.showCreateError" style="padding:0px;" class="col-md-6 alert alert-danger" role="alert"> + <span class="pull-right"> {{versionModalCtrl.error}}</span> + <span class="glyphicon glyphicon-exclamation-sign pull-right" aria-hidden="true" >Error:</span> + </div> + <button class="btn btn-primary" ng-click="versionModalCtrl.confirm()">Ok</button> + <button class="btn btn-default" ng-click="versionModalCtrl.cancel()">Cancel</button> + </div> + </div>
\ No newline at end of file diff --git a/testapi/opnfv_testapi/ui/components/scenarios/scenario/scenario.html b/testapi/opnfv_testapi/ui/components/scenarios/scenario/scenario.html new file mode 100644 index 0000000..328a5e6 --- /dev/null +++ b/testapi/opnfv_testapi/ui/components/scenarios/scenario/scenario.html @@ -0,0 +1,241 @@ +<legend>Scenario</legend> +<div style="padding-right:0px" class="col-md-12"> + <div class="table-responsive"> + <table class="table" ng-data="ctrl.data"> + <tbody> + <tr style="padding:9px"> + <td class="podsTableTd">Id :</td> + <td class="podsTableLeftTd">{{ctrl.data.scenarios[0]._id}}</td> + </tr> + <tr style="padding:9px"> + <td class="podsTableTd">Name :</td> + <td width="90%" class="podsTableLeftTd">{{ctrl.data.scenarios[0].name}}</td> + </tr> + <tr style="padding:9px"> + <td class="podsTableTd">Created at :</td> + <td width="90%" class="podsTableLeftTd">{{ctrl.data.scenarios[0].creation_date}}</td> + </tr> + <tr style="padding:9px"> + <td class="podsTableTd">Installers</td> + <td width="90%" class="podsTableLeftTd"> + <div class="col-md-1" style="padding:0px"> + <a ng-click="ctrl.expandInstallers()"> + <p ng-if="ctrl.collapeInstallers">Hide</p> + <p ng-if="!ctrl.collapeInstallers">Show</p> + </a> + </div> + <div class="col-md-1" style="padding:0px" ng-class="{'hidden' : !ctrl.buttonInstaller || !auth.isAuthenticated}"> + <button type="button" class="btn btn-success btn-xs" ng-click="ctrl.openAddInstaller()" ><i class="fa fa-plus"></i>Add</button> + </div> + <div ng-class="{ 'hidden' : ! ctrl.collapeInstallers } "> + <div class="table-responsive"> + <table class="table " ng-data="ctrl.data.scenarios[0].installers"> + <tbody ng-repeat="(indexI, installer) in ctrl.data.scenarios[0].installers"> + <tr style="padding:9px"> + <td class="podsTableTd"> + {{indexI+1}}. Installer: + </td> + <td class="podsTableLeftTd" style="width:10%;padding-top: 7px;"> + <a ng-click="ctrl.expandInstaller(indexI)">{{installer.installer}}</a> + </td> + <td style="width:80%;border: none; padding: 0px;" ng-class="{'hidden' : !ctrl.buttonInstaller}"> + <button type="button" ng-class="{'hidden' : !auth.isAuthenticated}" class="btn btn-danger btn-xs" ng-click="ctrl.openDeleteInstallerModal(installer.installer)" ><i class="fa fa-minus"></i>Delete</button> + </td> + </tr> + <tr ng-class="{ 'hidden' : ! ctrl.collapeInstaller[indexI] }"> + <td class="podsTableTd"> + Versions: + </td> + <td width="90%" class="podsTableLeftTd"> + <div class="col-md-1" style="padding:0px"> + <a ng-click="ctrl.expandVersions(indexI)"> + <p ng-if="ctrl.collapeVersions[indexI]">Hide</p> + <p ng-if="!ctrl.collapeVersions[indexI]">Show</p> + </a> + </div> + <div class="col-md-1" style="padding:0px" ng-class="{'hidden' : !ctrl.buttonVersion}"> + <button type="button" class="btn btn-success btn-xs" ng-class="{'hidden' : !auth.isAuthenticated}" ng-click="ctrl.openAddVersionModal(installer.installer)" ><i class="fa fa-plus"></i>Add</button> + </div> + <div ng-class="{ 'hidden' : ! ctrl.collapeVersions[indexI] } " class="col-md-12"> + <div class="table-responsive"> + <table class="table " ng-data="inctrl.data.scenarios[0].installers"> + <tbody ng-repeat="(indexV, version) in installer.versions"> + <tr style="padding:9px"> + <td class="podsTableTd"> + {{indexV+1}}. Version: + </td> + <td class="podsTableLeftTd" style="width:10%;padding-top: 7px;"> + <a ng-click="ctrl.expandVersion(indexI,indexV)">{{version.version}}</a> + </td> + <td style="width:80%;border: none; padding: 0px;" ng-class="{'hidden' : !ctrl.buttonVersion}"> + <button type="button" class="btn btn-danger btn-xs" ng-class="{'hidden' : !auth.isAuthenticated}" ng-click="ctrl.openDeleteVersionModal(version.version, installer.installer)" ><i class="fa fa-minus"></i>Delete</button> + </td> + </tr> + <tr style="padding:9px" ng-class="{ 'hidden' : ! ctrl.collapeVersion[indexI][indexV] } "> + <td class="podsTableTd"> + Owner: + </td> + <td class="podsTableLeftTd" style="width:90%">{{version.owner}}</td> + </tr> + <tr style="padding:9px" ng-class="{ 'hidden' : ! ctrl.collapeVersion[indexI][indexV] }"> + <td class="podsTableTd"> + Projects: + </td> + <td width="90%" class="podsTableLeftTd"> + <div class="col-md-1" style="padding:0px"> + <a ng-click="ctrl.expandProjects(indexI,indexV)"> + <p style="width:50%" ng-if="ctrl.collapeProjects[indexI][indexV]">Hide</p> + <p style="width:50%" ng-if="!ctrl.collapeProjects[indexI][indexV]">Show</p> + </a> + </div> + <div class="col-md-1" style="padding:0px" ng-class="{'hidden' : !ctrl.buttonProject }"> + <button type="button" ng-class="{'hidden' : !auth.isAuthenticated}" class="btn btn-success btn-xs" ng-click="ctrl.openAddProjectModal(version.version,installer.installer)" ><i class="fa fa-plus"></i>Add</button> + </div> + <div ng-class="{ 'hidden' : ! ctrl.collapeProjects[indexI][indexV] } " class="col-md-12"> + <div class="table-responsive"> + <table class="table " ng-data="version.projects"> + <tbody ng-repeat="(indexP, project) in version.projects" > + <tr style="padding:9px"> + <td class="podsTableTd"> + {{indexP+1}}. Project: + </td> + <td class="podsTableLeftTd" style="width:10%;padding-top: 7px;"> + <a ng-click="ctrl.expandProject(indexI, indexV, indexP)">{{project.project}}</a> + </td> + <td style="width:80%;border: none; padding: 0px;" ng-class="{'hidden' : !ctrl.buttonProject}"> + <button type="button" class="btn btn-danger btn-xs" ng-class="{'hidden' : !auth.isAuthenticated}" ng-click="ctrl.openDeleteProjectModal(project,version.version, installer.installer)" ><i class="fa fa-minus"></i>Delete</button> + </td> + </tr> + <tr ng-class="{ 'hidden' : ! ctrl.collapeProject[indexI][indexV][indexP] }"> + <td class="podsTableTd"> + Trust Indicators: + </td> + <td class="podsTableLeftTd" style="width:90%"> + <a ng-click="ctrl.expandTrustIndicator(indexI, indexV, indexP)"> + <p ng-if="ctrl.collapeTrustIndicator[indexI][indexV][indexP]">Hide</p> + <p ng-if="!ctrl.collapeTrustIndicator[indexI][indexV][indexP]">Show</p> + </a> + <table class="table " ng-class="{ 'hidden' : ! ctrl.collapeTrustIndicator[indexI][indexV][indexP] } " ng-data="project.trust_indicators"> + <tbody ng-repeat="(indexTI, trust_indicator) in project.trust_indicators" > + <tr style="padding:9px"> + <td class="podsTableTd"> + Status: + </td> + <td width="90%" class="podsTableLeftTd"> + {{trust_indicator.status}} + </td> + </tr> + <tr style="padding:9px"> + <td class="podsTableTd"> + Date: + </td> + <td width="90%" class="podsTableLeftTd"> + {{trust_indicator.date}} + </td> + </tr> + </tbody> + <tr> + <button type="button" class="btn btn-success btn-xs" ng-click="ctrl.openAddTrustIndicatorModal(project.project,version.version,installer.installer)" ng-class="{ 'hidden' : !ctrl.collapeTrustIndicator[index] || !auth.isAuthenticated}"> + <i class="fa fa-plus"></i>Add</button> + </tr> + </table> + </td> + </tr> + <tr ng-class="{ 'hidden' : ! ctrl.collapeProject[indexI][indexV][indexP] }"> + <td class="podsTableTd"> + Scores: + </td> + <td class="podsTableLeftTd" style="width:90%"> + <a ng-click="ctrl.expandScore(indexI, indexV, indexP)"> + <p ng-if="ctrl.collapeScore[indexI][indexV][indexP]">Hide</p> + <p ng-if="!ctrl.collapeScore[indexI][indexV][indexP]">Show</p> + </a> + <table class="table" ng-class="{ 'hidden' : ! ctrl.collapeScore[indexI][indexV][indexP] } " ng-data="project.scores"> + <tbody ng-repeat="(indexSC, score) in project.scores" > + <tr style="padding:9px"> + <td class="podsTableTd"> + Score: + </td> + <td width="90%" class="podsTableLeftTd"> + {{score.score}} + </td> + </tr> + <tr style="padding:9px"> + <td class="podsTableTd"> + Date: + </td> + <td width="90%" class="podsTableLeftTd"> + {{score.date}} + </td> + </tr> + </tbody> + <tr> + <button type="button" class="btn btn-success btn-xs" ng-click="ctrl.openAddScoreModal(project.project,version.version,installer.installer)" ng-class="{ 'hidden' : !ctrl.collapeScore[index] || !auth.isAuthenticated}"><i class="fa fa-plus"></i>Add</button> + </tr> + </table> + </td> + </tr> + <tr ng-class="{ 'hidden' : ! ctrl.collapeProject[indexI][indexV][indexP] }"> + <td class="podsTableTd"> + Customs: + </td> + <td class="podsTableLeftTd" style="width:90%"> + <a ng-click="ctrl.expandCustom(indexI, indexV, indexP)"> + <p ng-if="ctrl.collapeCustom[indexI][indexV][indexP]">Hide</p> + <p ng-if="!ctrl.collapeCustom[indexI][indexV][indexP]">Show</p> + </a> + <table class="table" ng-class="{ 'hidden' : ! ctrl.collapeCustom[indexI][indexV][indexP] } " ng-data="project.customs"> + <tbody> + <tr ng-repeat-start="(indexCU, custom) in project.customs" style="padding:9px"> + <td class="podsTableTd" style="float: none!important;"> + {{custom}} + </td> + <td width="90%" class="podsTableLeftTd"> + <button type="button" class="btn btn-danger btn-xs" ng-click="ctrl.openDeleteCustomModal(custom,project.project,version.version,installer.installer)" ng-class="{'hidden' : !auth.isAuthenticated}" ><i class="fa fa-minus"></i>Delete</button> + </td> + </tr> + <tr ng-repeat-end=> + </tr> + <tr> + <button type="button" class="btn btn-success btn-xs" ng-click="ctrl.openAddCustomModal(project.project,version.version,installer.installer)" ng-class="{ 'hidden' : !ctrl.collapeCustom[indexI][indexV][indexP] || !auth.isAuthenticated}"><i class="fa fa-plus"></i>Add</button> + </tr> + </tbody> + </table> + </td> + </tr> + <tr ng-repeat-end=> + </tr> + </tbody> + </table> + </div> + </div> + </td> + </tr> + </tbody> + </table> + </div> + </div> + </td> + </tr> + </tbody> + </table> + </div> + </div> + </td> + </tr> + </tbody> + </table> + </div> +</div> +<div class="row" style="margin-bottom:24px;"></div> +<div class='clo-md-12'> + <div ng-show="ctrl.showError" class="alert alert-danger" role="alert"> + <span class="pull-right"> {{ctrl.error}}</span> + <span class="glyphicon glyphicon-exclamation-sign pull-right" aria-hidden="true" >Error:</span> + </div> + <div ng-show="ctrl.showSuccess" class="alert alert-success" role="alert"> + <span class="pull-right"> {{ctrl.success}}</span> + <span class="glyphicon glyphicon-ok pull-right" aria-hidden="true"></span> + </div> +</div> +<div class="row" style="margin-bottom:24px;"></div>
\ No newline at end of file diff --git a/testapi/opnfv_testapi/ui/components/scenarios/scenario/scenarioController.js b/testapi/opnfv_testapi/ui/components/scenarios/scenario/scenarioController.js new file mode 100644 index 0000000..53eb13a --- /dev/null +++ b/testapi/opnfv_testapi/ui/components/scenarios/scenario/scenarioController.js @@ -0,0 +1,581 @@ +/* + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +(function () { + 'use strict'; + + angular + .module('testapiApp') + .controller('ScenarioController', ScenarioController); + + ScenarioController.$inject = [ + '$scope', '$http', '$filter', '$state', '$window', '$uibModal', 'testapiApiUrl','raiseAlert', + 'confirmModal' + ]; + + /** + * TestAPI Scenario Controller + * This controller is for the '/Scenario/:name' page where a user can browse + * through Scenario declared in TestAPI. + */ + function ScenarioController($scope, $http, $filter, $state, $window, $uibModal, testapiApiUrl, + raiseAlert, confirmModal) { + var ctrl = this; + ctrl.name = $state.params['name']; + ctrl.url = testapiApiUrl + '/scenarios?name=' + ctrl.name; + ctrl.expandInstallers = expandInstallers; + ctrl.expandInstaller = expandInstaller; + ctrl.expandInstaller = ctrl.expandInstaller; + ctrl.expandVersion = expandVersion; + ctrl.expandVersions = expandVersions; + ctrl.loadDetails = loadDetails; + ctrl.expandProjects = expandProjects + ctrl.expandProject = expandProject + ctrl.expandTrustIndicator = expandTrustIndicator; + ctrl.expandScore = expandScore; + ctrl.expandCustom = expandCustom; + ctrl.collapeVersion = []; + ctrl.collapeVersions = []; + ctrl.collapeProjects = []; + ctrl.collapeProject = []; + ctrl.collapeTrustIndicator = []; + ctrl.collapeScore = []; + ctrl.collapeCustom = []; + ctrl.collapeInstaller = []; + ctrl.addCustom = addCustom; + ctrl.openAddCustomModal = openAddCustomModal; + ctrl.openDeleteCustomModal = openDeleteCustomModal; + ctrl.deleteCustom = deleteCustom; + ctrl.addProject = addProject + ctrl.openAddProjectModal = openAddProjectModal + ctrl.openAddVersionModal = openAddVersionModal + ctrl.addVersion = addVersion + ctrl.openDeleteVersionModal = openDeleteVersionModal + ctrl.deleteVersion = deleteVersion + ctrl.openAddInstaller = openAddInstaller + ctrl.addInstaller = addInstaller + ctrl.openDeleteInstallerModal = openDeleteInstallerModal + ctrl.deleteInstaller = deleteInstaller + ctrl.openDeleteProjectModal = openDeleteProjectModal + ctrl.deleteProject = deleteProject + + ctrl.buttonInstaller = true + ctrl.buttonVersion = true + ctrl.buttonProject = true + + /** + * This will contact the TestAPI to get a listing of declared projects. + */ + function loadDetails() { + ctrl.showError = false; + ctrl.projectsRequest = + $http.get(ctrl.url).success(function (data) { + ctrl.data = data; + }).catch(function (error) { + ctrl.data = null; + ctrl.showError = true; + ctrl.error = error.statusText + }); + } + + function expandTrustIndicator(indexI, indexV, indexP){ + if(ctrl.collapeTrustIndicator[indexI]==undefined){ + ctrl.collapeTrustIndicator[indexI] = [] + if(ctrl.collapeTrustIndicator[indexI][indexV]==undefined){ + ctrl.collapeTrustIndicator[indexI][indexV] = [] + } + } + if(ctrl.collapeTrustIndicator[indexI][indexV][indexP]){ + ctrl.collapeTrustIndicator[indexI][indexV][indexP] = false; + }else{ + ctrl.collapeTrustIndicator[indexI][indexV][indexP] = true; + } + } + + function expandScore(indexI, indexV, indexP){ + if(ctrl.collapeScore[indexI]==undefined){ + ctrl.collapeScore[indexI] = [] + if(ctrl.collapeScore[indexI][indexV]==undefined){ + ctrl.collapeScore[indexI][indexV] = [] + } + } + if(ctrl.collapeScore[indexI][indexV][indexP]){ + ctrl.collapeScore[indexI][indexV][indexP] = false; + }else{ + ctrl.collapeScore[indexI][indexV][indexP] = true; + } + } + + function expandCustom(indexI, indexV, indexP){ + if(ctrl.collapeCustom[indexI]==undefined){ + ctrl.collapeCustom[indexI] = [] + if(ctrl.collapeCustom[indexI][indexV]==undefined){ + ctrl.collapeCustom[indexI][indexV] = [] + } + } + if(ctrl.collapeCustom[indexI][indexV][indexP]){ + ctrl.collapeCustom[indexI][indexV][indexP] = false; + ctrl.buttonProject = true + }else{ + ctrl.collapeCustom[indexI][indexV][indexP] = true; + ctrl.buttonProject = false + } + } + + function expandVersion(indexI, indexV){ + if(ctrl.collapeVersion[indexI]==undefined){ + ctrl.collapeVersion[indexI] = [] + } + if(ctrl.collapeVersion[indexI][indexV]){ + ctrl.collapeVersion[indexI][indexV] = false; + }else{ + ctrl.collapeVersion[indexI][indexV] = true; + } + } + + function expandVersions(index){ + if(ctrl.collapeVersions[index]){ + ctrl.collapeVersions[index] = false; + ctrl.buttonInstaller = true + }else{ + ctrl.collapeVersions[index] = true; + ctrl.buttonInstaller = false + } + } + + function expandProjects(indexI, indexV){ + if(ctrl.collapeProjects[indexI]==undefined){ + ctrl.collapeProjects[indexI] = [] + } + if(ctrl.collapeProjects[indexI][indexV]){ + ctrl.collapeProjects[indexI][indexV] = false; + ctrl.buttonVersion = true + } + else{ + ctrl.collapeProjects[indexI][indexV]= true; + ctrl.buttonVersion = false + } + } + + function expandProject(indexI, indexV, indexP){ + if(ctrl.collapeProject[indexI]==undefined){ + ctrl.collapeProject[indexI] = [] + if(ctrl.collapeProject[indexI][indexV]==undefined){ + ctrl.collapeProject[indexI][indexV] = [] + } + } + if(ctrl.collapeProject[indexI][indexV][indexP]){ + ctrl.collapeProject[indexI][indexV][indexP] = false; + } + else{ + ctrl.collapeProject[indexI][indexV][indexP]= true; + } + } + + function expandInstaller(index){ + if(ctrl.collapeInstaller[index]){ + ctrl.collapeInstaller[index] = false; + } + else{ + ctrl.collapeInstaller[index]= true; + } + } + + function expandInstallers(){ + if(ctrl.collapeInstallers){ + ctrl.collapeInstallers= false + }else{ + ctrl.collapeInstallers= true + } + } + + function deleteInstaller(data){ + ctrl.installerReqest = testapiApiUrl+ "/scenarios/"+ ctrl.name + "/installers" + $http.delete(ctrl.installerReqest, {data: data.installers, headers: {'Content-Type': 'application/json'}}).success(function (data){ + ctrl.showSuccess = true ; + ctrl.success = "Installer is successfully deleted." + ctrl.loadDetails(); + }) + .catch(function (data) { + ctrl.showError = true; + ctrl.error = data.statusText; + }); + } + + function openDeleteInstallerModal(installer){ + var installers = [] + installers.push(installer) + var data = { + "installers": installers + } + confirmModal("Delete",ctrl.deleteInstaller,data); + } + + function addInstaller(installer){ + var installers = [] + installers.push(installer) + ctrl.installerReqest = testapiApiUrl+ "/scenarios/"+ ctrl.name + "/installers" + $http.post(ctrl.installerReqest, installers).success(function (data){ + ctrl.showSuccess = true ; + ctrl.success = "Installers are successfully updated." + ctrl.loadDetails(); + }) + .catch(function (data) { + ctrl.showError = true; + ctrl.error = data.statusText; + }); + } + + function openAddInstaller(){ + $uibModal.open({ + templateUrl: 'testapi-ui/components/scenarios/modals/installerModal.html', + controller: 'installerModalCtrl as installerModalCtrl', + size: 'md', + resolve: { + data: function () { + return { + text: "Add Installer", + successHandler: ctrl.addInstaller + }; + } + } + }); + } + + function addVersion(versions, installer){ + ctrl.versionReqest = testapiApiUrl+ "/scenarios/"+ ctrl.name + "/versions?installer="+installer + $http.post(ctrl.versionReqest, versions).success(function (data){ + ctrl.showSuccess = true ; + ctrl.success = "Versions are successfully updated." + ctrl.loadDetails(); + }) + .catch(function (data) { + ctrl.showError = true; + ctrl.error = data.statusText; + }); + } + + function openDeleteVersionModal(version, installer){ + var versions = [] + versions.push(version) + var data = { + "version": versions, + "installer": installer + } + confirmModal("Delete",ctrl.deleteVersion,data); + } + + function deleteVersion(data){ + ctrl.versionReqest = testapiApiUrl+ "/scenarios/"+ ctrl.name + "/versions?installer="+data.installer + $http.delete(ctrl.versionReqest, {data: data.version, headers: {'Content-Type': 'application/json'}}).success(function (data){ + ctrl.showSuccess = true ; + ctrl.success = "Versions are successfully deleted." + ctrl.loadDetails(); + }) + .catch(function (data) { + ctrl.showError = true; + ctrl.error = data.statusText; + }); + } + + function openAddVersionModal(installer){ + $uibModal.open({ + templateUrl: 'testapi-ui/components/scenarios/modals/versionModal.html', + controller: 'versionAddModalCtrl as versionModalCtrl', + size: 'md', + resolve: { + data: function () { + return { + text: "Add Version", + successHandler: ctrl.addVersion, + installer: installer + }; + } + } + }); + } + + function addProject(project, version, installer){ + ctrl.projectReqest = testapiApiUrl+ "/scenarios/"+ ctrl.name + "/projects?installer="+installer+"&version="+version + $http.post(ctrl.projectReqest, project).success(function (data){ + ctrl.showSuccess = true ; + ctrl.success = "Projects are successfully updated." + ctrl.loadDetails(); + }) + .catch(function (data) { + ctrl.showError = true; + ctrl.error = data.statusText; + }); + } + + function openAddProjectModal(version, installer){ + $uibModal.open({ + templateUrl: 'testapi-ui/components/scenarios/modals/projectModal.html', + controller: 'projectAddModalCtrl as projectModalCtrl', + size: 'md', + resolve: { + data: function () { + return { + text: "Add Project", + successHandler: ctrl.addProject, + version: version, + installer: installer + }; + } + } + }); + } + + function addCustom(custom,project,version,installer){ + ctrl.customReqest = testapiApiUrl+ "/scenarios/"+ ctrl.name + "/customs?installer="+installer+"&version="+version+"&project="+ project + $http.post(ctrl.customReqest, custom).success(function (data){ + ctrl.showSuccess = true ; + ctrl.success = "Customs are successfully updated." + ctrl.loadDetails(); + }) + .catch(function (data) { + ctrl.showError = true; + ctrl.error = data.statusText; + }); + } + + function openDeleteCustomModal(custom,project,version,installer){ + var customs = [] + customs.push(custom) + var data = { + "customs": customs, + "project": project, + "version": version, + "installer": installer + } + confirmModal("Delete",ctrl.deleteCustom,data); + } + + function deleteCustom(data){ + ctrl.customReqest = testapiApiUrl+ "/scenarios/"+ ctrl.name + "/customs?installer="+data.installer+"&version="+data.version+"&project="+ data.project + $http.delete(ctrl.customReqest, {data: data.customs, headers: {'Content-Type': 'application/json'}}).success(function (data){ + ctrl.showSuccess = true ; + ctrl.success = "Customs are successfully deleted." + ctrl.loadDetails(); + }) + .catch(function (data) { + ctrl.showError = true; + ctrl.error = data.statusText; + }); + } + + function openAddCustomModal(project,version,installer){ + $uibModal.open({ + templateUrl: 'testapi-ui/components/scenarios/modals/customModal.html', + controller: 'customAddModalCtrl as customModalCtrl', + size: 'md', + resolve: { + data: function () { + return { + text: "Add Custom", + successHandler: ctrl.addCustom, + project: project, + version: version, + installer: installer + }; + } + } + }); + } + + function openDeleteProjectModal(project, version, installer){ + var projects = [] + projects.push(project.project) + var data = { + "projects": projects, + "version": version, + "installer": installer + } + confirmModal("Delete",ctrl.deleteProject,data); + } + + function deleteProject(data){ + ctrl.projectReqest = testapiApiUrl+ "/scenarios/"+ ctrl.name + "/projects?installer="+data.installer+"&version="+data.version + $http.delete(ctrl.projectReqest, {data: data.projects, headers: {'Content-Type': 'application/json'}}).success(function (data){ + ctrl.showSuccess = true ; + ctrl.success = "Projects are successfully Deleted." + ctrl.loadDetails(); + }) + .catch(function (data) { + ctrl.showError = true; + ctrl.error = data.statusText; + }); + } + + ctrl.loadDetails(); + } + + /** + * TestAPI Project Modal Controller + * This controller is for the create modal where a user can create + * the project information and for the edit modal where user can + * edit the project's details + */ + angular.module('testapiApp').controller('customAddModalCtrl', customAddModalCtrl); + customAddModalCtrl.$inject = ['$scope', '$uibModalInstance', 'data']; + function customAddModalCtrl($scope, $uibModalInstance, data) { + var ctrl = this; + ctrl.confirm = confirm; + ctrl.cancel = cancel; + ctrl.data = angular.copy(data); + ctrl.open = open; + + + /** + * Initiate confirmation and call the success handler with the + * inputs. + */ + function confirm() { + ctrl.customs = [] + ctrl.customs.push(ctrl.custom) + ctrl.data.successHandler(ctrl.customs,ctrl.data.project,ctrl.data.version,ctrl.data.installer); + $uibModalInstance.dismiss('cancel'); + + } + + /** + * Close the confirm modal without initiating changes. + */ + function cancel() { + $uibModalInstance.dismiss('cancel'); + } + } + + + /** + * TestAPI Project Modal Controller + * This controller is for the create modal where a user can create + * the project information and for the edit modal where user can + * edit the project's details + */ + angular.module('testapiApp').controller('projectAddModalCtrl', projectAddModalCtrl); + projectAddModalCtrl.$inject = ['$scope', '$uibModal', '$uibModalInstance', 'data']; + function projectAddModalCtrl($scope, $uibModal, $uibModalInstance, data) { + var ctrl = this; + ctrl.confirm = confirm; + ctrl.cancel = cancel; + ctrl.data = angular.copy(data); + ctrl.openCustomModal = openCustomModal; + ctrl.handleModalCustom = handleModalCustom; + ctrl.projects = [] + ctrl.project = { + "scores": [], + "trust_indicators": [], + "customs": [] + } + + + /** + * Initiate confirmation and call the success handler with the + * inputs. + */ + function confirm() { + ctrl.projects.push(ctrl.project) + ctrl.data.successHandler(ctrl.projects, ctrl.data.version, ctrl.data.installer); + $uibModalInstance.dismiss('cancel'); + + } + + /** + * Close the confirm modal without initiating changes. + */ + function cancel() { + $uibModalInstance.dismiss('cancel'); + } + + function handleModalCustom(custom){ + ctrl.project.customs.push(custom); + } + + function openCustomModal(){ + $uibModal.open({ + templateUrl: 'testapi-ui/components/scenarios/modals/customModal.html', + controller: 'customModalCtrl as customModalCtrl', + size: 'md', + resolve: { + data: function () { + return { + text: "Custom", + successHandler: ctrl.handleModalCustom + }; + } + } + }); + } + } + + /** + * TestAPI Project Modal Controller + * This controller is for the create modal where a user can create + * the project information and for the edit modal where user can + * edit the project's details + */ + angular.module('testapiApp').controller('versionAddModalCtrl', versionAddModalCtrl); + versionAddModalCtrl.$inject = ['$scope', '$uibModal','$uibModalInstance', 'data']; + function versionAddModalCtrl($scope, $uibModal, $uibModalInstance, data) { + var ctrl = this; + ctrl.confirm = confirm; + ctrl.cancel = cancel; + ctrl.data = angular.copy(data); + ctrl.openProjectModal = openProjectModal; + ctrl.handleModalData = handleModalData; + ctrl.versions = [] + ctrl.version = { + "projects": [] + } + + /** + * Initiate confirmation and call the success handler with the + * inputs. + */ + function confirm() { + ctrl.versions.push(ctrl.version) + ctrl.data.successHandler(ctrl.versions, ctrl.data.installer); + $uibModalInstance.dismiss('cancel'); + + } + + /** + * Close the confirm modal without initiating changes. + */ + function cancel() { + $uibModalInstance.dismiss('cancel'); + } + + function handleModalData(project){ + ctrl.version.projects.push(project) + } + function openProjectModal(){ + $uibModal.open({ + templateUrl: 'testapi-ui/components/scenarios/modals/projectModal.html', + controller: 'projectModalCtrl as projectModalCtrl', + size: 'md', + resolve: { + data: function () { + return { + text: "Project", + successHandler: ctrl.handleModalData, + }; + } + } + }); + } + } + +})(); diff --git a/testapi/opnfv_testapi/ui/components/scenarios/scenarios.html b/testapi/opnfv_testapi/ui/components/scenarios/scenarios.html new file mode 100644 index 0000000..9057b0f --- /dev/null +++ b/testapi/opnfv_testapi/ui/components/scenarios/scenarios.html @@ -0,0 +1,60 @@ +<h3>Scenarios</h3> +<div class="row" style="margin-bottom:24px;"></div> +<div class="row podsTable" style="vertical-align:middle"> + <div class="col-sm-1 pull-right" ng-class="{ 'hidden': !auth.isAuthenticated }" > + <button type="button" class="btn btn-danger" ng-click="ctrl.openBatchDeleteModal()"> + <i class="fa fa-minus"></i> Delete</button> + </div> + <div class="col-sm-2 pull-right" ng-class="{ 'hidden': !auth.isAuthenticated}"> + <button type="button" class="btn btn-success" ng-click="ctrl.openScenarioModal()"> + <i class="fa fa-plus"></i>Create</button> + </div> +</div> +<div class='clo-md-12'> + <div ng-show="ctrl.showError" class="alert alert-danger" role="alert"> + <span class="pull-right"> {{ctrl.error}}</span> + <span class="glyphicon glyphicon-exclamation-sign pull-right" aria-hidden="true" >Error:</span> + </div> + <div ng-show="ctrl.showCreateSuccess" class="alert alert-success" role="alert"> + <span class="pull-right"> {{ctrl.success}}</span> + <span class="glyphicon glyphicon-ok pull-right" aria-hidden="true"></span> + </div> +</div> +<div class='clo-md-12' style="padding-right:0px"> + <div class="table-responsive"> + <table class="table table-bordered table-hover" ng-data="ctrl.data.scenarios"> + <thead> + <tr style=" + text-align: center;"> + <th style="width: 1%;">Bulk Select</th> + <th style="width: 80%;">Name</th> + <th style="width: 19%;" ng-class="{'hidden': !auth.isAuthenticated}">Operations</th> + </tr> + </thead> + <tbody> + <tr ng-repeat-start="(index, scenario) in ctrl.data.scenarios" style="padding:9px"> + <td> + <div class="text-center"> + <input type="checkbox" value="{{scenario.name}}" ng-model="ctrl.checkBox[index]" > + </div> + </td> + <td> + <a class="text-info" ng-click="ctrl.viewScenario(scenario.name)"> + {{scenario.name}} + </a> + </td> + <td ng-class="{'hidden': !auth.isAuthenticated}"> + <span class="podsTable-col"> + <a class="text-warning" ng-click="ctrl.openUpdateModal(scenario.name)" title="Edit"> + <i class="fa fa-pencil-square-o"></i></a> + <a class="text-danger" ng-click="ctrl.openDeleteModal(scenario.name)" title="Delete"> + <i class="fa fa-trash-o"></i></a> + </span> + </td> + <tr ng-repeat-end=> + </tr> + </tbody> + </table> + </div> +</div> + diff --git a/testapi/opnfv_testapi/ui/components/scenarios/scenariosController.js b/testapi/opnfv_testapi/ui/components/scenarios/scenariosController.js new file mode 100644 index 0000000..fd137e5 --- /dev/null +++ b/testapi/opnfv_testapi/ui/components/scenarios/scenariosController.js @@ -0,0 +1,467 @@ +/* + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +(function () { + 'use strict'; + + angular + .module('testapiApp') + .controller('ScenariosController', ScenariosController); + + ScenariosController.$inject = [ + '$scope', '$http', '$filter', '$state', '$window', '$uibModal', 'testapiApiUrl', + 'raiseAlert', 'confirmModal' + ]; + + /** + * TestAPI Project Controller + * This controller is for the '/projects' page where a user can browse + * through projects declared in TestAPI. + */ + function ScenariosController($scope, $http, $filter, $state, $window, $uibModal, testapiApiUrl, + raiseAlert, confirmModal) { + var ctrl = this; + ctrl.url = testapiApiUrl + '/scenarios'; + + ctrl.createScenario = createScenario; + ctrl.listScenarios = listScenarios; + ctrl.openScenarioModal = openScenarioModal; + ctrl.viewScenario = viewScenario; + ctrl.openUpdateModal = openUpdateModal; + ctrl.updateScenarioName = updateScenarioName; + ctrl.openDeleteModal = openDeleteModal; + ctrl.deleteScenario = deleteScenario; + ctrl.openBatchDeleteModal = openBatchDeleteModal; + ctrl.deleteBatchScenario = deleteBatchScenario + + ctrl.checkBox = []; + + function openUpdateModal(name){ + $uibModal.open({ + templateUrl: 'testapi-ui/components/scenarios/modals/scenarioNameUpdate.html', + controller: 'ScenarioNameUpdateCtrl as ScenarioNameUpdateCtrl', + size: 'md', + resolve: { + data: function () { + return { + text: "Name Change: Scenario", + successHandler: ctrl.updateScenarioName, + name: name + }; + } + } + }); + } + + function openDeleteModal(name){ + confirmModal("Delete",ctrl.deleteScenario,name); + } + + function deleteScenario(name){ + var scenarioURL = ctrl.url+"/"+name; + ctrl.scenarioRequest = + $http.delete(scenarioURL).success(function (data){ + ctrl.showCreateSuccess = true; + ctrl.success = "Scenario is successfully deleted."; + ctrl.listScenarios(); + }).catch(function (data) { + ctrl.showError = true; + ctrl.error = data.statusText; + }); + } + + function openBatchDeleteModal(){ + confirmModal("Delete",ctrl.deleteBatchScenario); + } + + function deleteBatchScenario(){ + var index; + var checkedBox = []; + ctrl.checkBox.forEach(function(project, index){ + if(!ctrl.showError){ + if(project){ + deleteScenario(ctrl.data.scenarios[index].name); + } + } + }); + ctrl.checkBox = [] + } + + function updateScenarioName(newName, name){ + var scenarioURL = ctrl.url+"/"+name + var body = { + "name": newName + } + ctrl.scenarioRequest = + $http.put(scenarioURL, body).success(function (data){ + ctrl.showCreateSuccess = true; + ctrl.success = "Scenario is successfully Updated." + ctrl.listScenarios() + }).catch(function (data) { + ctrl.showError = true; + ctrl.error = data.statusText; + }); + } + + function viewScenario(name){ + $state.go('scenario', {'name':name}, {reload: true}); + } + + function createScenario(scenario) { + console.log(scenario) + ctrl.scenarioRequest = + $http.post(ctrl.url, scenario).success(function (data){ + ctrl.showCreateSuccess = true; + ctrl.success = "Scenario is successfully created." + }).catch(function (data) { + ctrl.showError = true; + ctrl.error = data.statusText; + }); + } + + function listScenarios() { + ctrl.showError = false; + ctrl.resultsRequest = + $http.get(ctrl.url).success(function (data) { + ctrl.data = data; + }).catch(function (data) { + ctrl.data = null; + ctrl.showError = true; + ctrl.error = data.statusText; + }); + } + + function openScenarioModal(){ + $uibModal.open({ + templateUrl: 'testapi-ui/components/scenarios/modals/scenarioModal.html', + controller: 'scenarioModalController as scenarioModalController', + size: 'md', + resolve: { + data: function () { + return { + text: "Scenario", + successHandler: ctrl.createScenario, + }; + } + } + }); + } + + listScenarios(); + } + + + /** + * TestAPI Project Modal Controller + * This controller is for the create modal where a user can create + * the project information and for the edit modal where user can + * edit the project's details + */ + angular.module('testapiApp').controller('scenarioModalController', scenarioModalController); + scenarioModalController.$inject = ['$scope', '$uibModal', '$uibModalInstance', 'data']; + function scenarioModalController($scope, $uibModal, $uibModalInstance, data) { + var ctrl = this; + ctrl.confirm = confirm; + ctrl.cancel = cancel; + ctrl.data = angular.copy(data); + ctrl.handleModalData = handleModalData; + ctrl.openInstallerModal = openInstallerModal; + ctrl.scenario = { + "installers": [], + } + + + /** + * Initiate confirmation and call the success handler with the + * inputs. + */ + function confirm() { + ctrl.data.successHandler(ctrl.scenario); + $uibModalInstance.dismiss('cancel'); + + } + + /** + * Close the confirm modal without initiating changes. + */ + function cancel() { + $uibModalInstance.dismiss('cancel'); + } + + function handleModalData(installer){ + ctrl.scenario.installers.push(installer) + } + + function openInstallerModal(){ + $uibModal.open({ + templateUrl: 'testapi-ui/components/scenarios/modals/installerModal.html', + controller: 'installerModalCtrl as installerModalCtrl', + size: 'md', + resolve: { + data: function () { + return { + text: "Installer", + successHandler: ctrl.handleModalData, + }; + } + } + }); + } + } + + /** + * TestAPI Project Modal Controller + * This controller is for the create modal where a user can create + * the project information and for the edit modal where user can + * edit the project's details + */ + angular.module('testapiApp').controller('installerModalCtrl', installerModalCtrl); + installerModalCtrl.$inject = ['$scope', '$uibModal', '$uibModalInstance', 'data']; + function installerModalCtrl($scope, $uibModal, $uibModalInstance, data) { + var ctrl = this; + ctrl.confirm = confirm; + ctrl.cancel = cancel; + ctrl.data = angular.copy(data); + ctrl.openVersionModal = openVersionModal; + ctrl.handleModalData = handleModalData; + ctrl.installer = { + "versions":[] + } + + + /** + * Initiate confirmation and call the success handler with the + * inputs. + */ + function confirm() { + ctrl.data.successHandler(ctrl.installer); + $uibModalInstance.dismiss('cancel'); + + } + + /** + * Close the confirm modal without initiating changes. + */ + function cancel() { + $uibModalInstance.dismiss('cancel'); + } + + function handleModalData(version){ + ctrl.installer.versions.push(version); + } + + function openVersionModal(){ + console.log("Hello"); + $uibModal.open({ + templateUrl: 'testapi-ui/components/scenarios/modals/versionModal.html', + controller: 'versionModalCtrl as versionModalCtrl', + size: 'md', + resolve: { + data: function () { + return { + text: "Version", + successHandler: ctrl.handleModalData, + }; + } + } + }); + } + } + + /** + * TestAPI Project Modal Controller + * This controller is for the create modal where a user can create + * the project information and for the edit modal where user can + * edit the project's details + */ + angular.module('testapiApp').controller('versionModalCtrl', versionModalCtrl); + versionModalCtrl.$inject = ['$scope', '$uibModal','$uibModalInstance', 'data']; + function versionModalCtrl($scope, $uibModal, $uibModalInstance, data) { + var ctrl = this; + ctrl.confirm = confirm; + ctrl.cancel = cancel; + ctrl.data = angular.copy(data); + ctrl.openProjectModal = openProjectModal; + ctrl.handleModalData = handleModalData; + ctrl.version = { + "projects": [] + } + + /** + * Initiate confirmation and call the success handler with the + * inputs. + */ + function confirm() { + ctrl.data.successHandler(ctrl.version); + $uibModalInstance.dismiss('cancel'); + + } + + /** + * Close the confirm modal without initiating changes. + */ + function cancel() { + $uibModalInstance.dismiss('cancel'); + } + + function handleModalData(project){ + ctrl.version.projects.push(project) + } + function openProjectModal(){ + $uibModal.open({ + templateUrl: 'testapi-ui/components/scenarios/modals/projectModal.html', + controller: 'projectModalCtrl as projectModalCtrl', + size: 'md', + resolve: { + data: function () { + return { + text: "Project", + successHandler: ctrl.handleModalData, + }; + } + } + }); + } + } + + /** + * TestAPI Project Modal Controller + * This controller is for the create modal where a user can create + * the project information and for the edit modal where user can + * edit the project's details + */ + angular.module('testapiApp').controller('projectModalCtrl', projectModalCtrl); + projectModalCtrl.$inject = ['$scope', '$uibModal', '$uibModalInstance', 'data']; + function projectModalCtrl($scope, $uibModal, $uibModalInstance, data) { + var ctrl = this; + ctrl.confirm = confirm; + ctrl.cancel = cancel; + ctrl.data = angular.copy(data); + ctrl.openCustomModal = openCustomModal; + ctrl.handleModalCustom = handleModalCustom; + ctrl.project = { + "scores": [], + "trust_indicators": [], + "customs": [] + } + + + /** + * Initiate confirmation and call the success handler with the + * inputs. + */ + function confirm() { + + ctrl.data.successHandler(ctrl.project); + $uibModalInstance.dismiss('cancel'); + + } + + /** + * Close the confirm modal without initiating changes. + */ + function cancel() { + $uibModalInstance.dismiss('cancel'); + } + + function handleModalCustom(custom){ + ctrl.project.customs.push(custom); + } + + function openCustomModal(){ + $uibModal.open({ + templateUrl: 'testapi-ui/components/scenarios/modals/customModal.html', + controller: 'customModalCtrl as customModalCtrl', + size: 'md', + resolve: { + data: function () { + return { + text: "Custom", + successHandler: ctrl.handleModalCustom + }; + } + } + }); + } + } + + /** + * TestAPI Project Modal Controller + * This controller is for the create modal where a user can create + * the project information and for the edit modal where user can + * edit the project's details + */ + angular.module('testapiApp').controller('customModalCtrl', customModalCtrl); + customModalCtrl.$inject = ['$scope', '$uibModalInstance', 'data']; + function customModalCtrl($scope, $uibModalInstance, data) { + var ctrl = this; + ctrl.confirm = confirm; + ctrl.cancel = cancel; + ctrl.data = angular.copy(data); + ctrl.open = open; + + + /** + * Initiate confirmation and call the success handler with the + * inputs. + */ + function confirm() { + ctrl.data.successHandler(ctrl.custom); + $uibModalInstance.dismiss('cancel'); + + } + + /** + * Close the confirm modal without initiating changes. + */ + function cancel() { + $uibModalInstance.dismiss('cancel'); + } + } + + /** + * TestAPI Project Modal Controller + * This controller is for the create modal where a user can create + * the project information and for the edit modal where user can + * edit the project's details + */ + angular.module('testapiApp').controller('ScenarioNameUpdateCtrl', ScenarioNameUpdateCtrl); + ScenarioNameUpdateCtrl.$inject = ['$scope', '$uibModalInstance', 'data']; + function ScenarioNameUpdateCtrl($scope, $uibModalInstance, data) { + var ctrl = this; + ctrl.confirm = confirm; + ctrl.cancel = cancel; + ctrl.data = angular.copy(data); + ctrl.open = open; + ctrl.name = ctrl.data.name; + + + /** + * Initiate confirmation and call the success handler with the + * inputs. + */ + function confirm() { + ctrl.data.successHandler(ctrl.name,ctrl.data.name); + $uibModalInstance.dismiss('cancel'); + + } + + /** + * Close the confirm modal without initiating changes. + */ + function cancel() { + $uibModalInstance.dismiss('cancel'); + } + } +})(); diff --git a/testapi/opnfv_testapi/ui/config.json b/testapi/opnfv_testapi/ui/config.json index 5d48c7b..26dfd08 100644 --- a/testapi/opnfv_testapi/ui/config.json +++ b/testapi/opnfv_testapi/ui/config.json @@ -1 +1,2 @@ -{"testapiApiUrl": "http://localhost:8000/api/v1"} +{"testapiApiUrl": "http://localhost:8000/api/v1", +"authenticate": true} diff --git a/testapi/opnfv_testapi/ui/index.html b/testapi/opnfv_testapi/ui/index.html index 3191858..beec61d 100644 --- a/testapi/opnfv_testapi/ui/index.html +++ b/testapi/opnfv_testapi/ui/index.html @@ -44,13 +44,18 @@ <script src="testapi-ui/shared/alerts/alertModalFactory.js"></script> <script src="testapi-ui/shared/alerts/confirmModalFactory.js"></script> <script src="testapi-ui/components/pods/podsController.js"></script> + <script src="testapi-ui/components/scenarios/scenario/scenarioController.js"></script> + <script src="testapi-ui/components/scenarios/scenariosController.js"></script> <script src="testapi-ui/components/pods/pod/podController.js"></script> <script src="testapi-ui/components/projects/projectsController.js"></script> <script src="testapi-ui/components/projects/project/projectController.js"></script> <script src="testapi-ui/components/results/resultsController.js"></script> + <script src="testapi-ui/components/results/result/resultController.js"></script> <script src="testapi-ui/components/profile/profileController.js"></script> <script src="testapi-ui/components/auth-failure/authFailureController.js"></script> <script src="testapi-ui/components/logout/logoutController.js"></script> + <script src="testapi-ui/components/projects/project/testCases/testCasesController.js"></script> + <script src="testapi-ui/components/projects/project/testCases/testCase/testCaseController.js"></script> <!-- Filters --> <script src="testapi-ui/shared/filters.js"></script> diff --git a/testapi/opnfv_testapi/ui/shared/alerts/confirmModalFactory.js b/testapi/opnfv_testapi/ui/shared/alerts/confirmModalFactory.js index fc0bfe6..5e79775 100644 --- a/testapi/opnfv_testapi/ui/shared/alerts/confirmModalFactory.js +++ b/testapi/opnfv_testapi/ui/shared/alerts/confirmModalFactory.js @@ -46,7 +46,6 @@ ctrl.cancel = cancel; ctrl.data = angular.copy(data); - console.log(ctrl.data) /** * Initiate confirmation and call the success handler with the * input text. diff --git a/testapi/opnfv_testapi/ui/shared/header/header.html b/testapi/opnfv_testapi/ui/shared/header/header.html index d0501a2..3b2aba1 100644 --- a/testapi/opnfv_testapi/ui/shared/header/header.html +++ b/testapi/opnfv_testapi/ui/shared/header/header.html @@ -19,9 +19,10 @@ TestAPI <li ng-class="{ active: header.isActive('/about')}"><a ui-sref="about">About</a></li> <li ng-class="{ active: header.isActive('/pods')}"><a ui-sref="pods">Pods</a></li> <li ng-class="{ active: header.isActive('/projects')}"><a ui-sref="projects">Projects</a></li> - <li ng-class="{ active: header.isActive('/results')}"><a ui-sref="results">Results</a></li> + <li ng-class="{ active: header.isActive('/results')}"><a ui-sref="results">Results</a></li> + <li ng-class="{ active: header.isActive('/scenarios')}"><a ui-sref="scenarios">Scenarios</a></li> </ul> - <ul class="nav navbar-nav navbar-right"> + <ul class="nav navbar-nav navbar-right" ng-class="{'hidden' : !authenticate}"> <li ng-class="{ active: header.isActive('/profile')}" ng-if="auth.isAuthenticated"><a ui-sref="profile">Profile</a></li> <li ng-if="auth.isAuthenticated"><a href="" ng-click="auth.doSignOut()">Sign Out</a></li> <li ng-if="!auth.isAuthenticated"><a href="" ng-click="auth.doSignIn()">Sign In / Sign Up</a></li> diff --git a/testapi/requirements.txt b/testapi/requirements.txt index fbd2e0e..f752a64 100644 --- a/testapi/requirements.txt +++ b/testapi/requirements.txt @@ -9,3 +9,4 @@ epydoc>=0.3.1 six>=1.9.0 # MIT motor # Apache-2.0 python-cas +requests[security]
\ No newline at end of file |