aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--INFO31
-rw-r--r--docker/Dockerfile5
-rw-r--r--docker/Dockerfile.aarch643
-rwxr-xr-xdocker/add_images.sh11
-rw-r--r--docs/com/pres/framework/framework.html52
-rw-r--r--docs/com/pres/framework/framework.md268
-rw-r--r--docs/results/danube/2.0/apex.html1057
-rw-r--r--docs/results/danube/2.0/compass.html493
-rw-r--r--docs/results/danube/2.0/fuel.html1447
-rw-r--r--docs/results/danube/2.0/joid.html421
-rw-r--r--docs/results/danube/2.0/scenario_history.txt1454
-rw-r--r--docs/results/danube/2.0/validated_scenario_history.txt212
-rw-r--r--docs/testing/user/configguide/configguide.rst1
-rw-r--r--docs/testing/user/userguide/index.rst120
-rwxr-xr-xfunctest/ci/check_os.sh24
-rw-r--r--functest/ci/config_functest.yaml39
-rw-r--r--functest/ci/download_images.sh31
-rwxr-xr-xfunctest/ci/generate_report.py153
-rw-r--r--functest/ci/logging.ini75
-rw-r--r--functest/ci/logging.json29
-rwxr-xr-xfunctest/ci/prepare_env.py162
-rwxr-xr-xfunctest/ci/run_tests.py101
-rw-r--r--functest/ci/testcases.yaml59
-rw-r--r--functest/ci/tier_builder.py11
-rw-r--r--functest/ci/tier_handler.py5
-rw-r--r--functest/cli/cli_base.py6
-rw-r--r--functest/cli/commands/cli_env.py20
-rw-r--r--functest/cli/commands/cli_os.py15
-rw-r--r--functest/cli/commands/cli_testcase.py13
-rw-r--r--functest/cli/commands/cli_tier.py13
-rw-r--r--functest/core/feature.py18
-rw-r--r--functest/core/pytest_suite_runner.py42
-rw-r--r--functest/core/testcase.py68
-rw-r--r--functest/core/vnf.py (renamed from functest/core/vnf_base.py)63
-rw-r--r--functest/energy/__init__.py0
-rw-r--r--functest/energy/energy.py203
-rw-r--r--functest/opnfv_tests/features/barometer.py6
-rwxr-xr-xfunctest/opnfv_tests/openstack/examples/create_instance_and_ip.py128
-rw-r--r--functest/opnfv_tests/openstack/rally/rally.py26
-rw-r--r--functest/opnfv_tests/openstack/refstack_client/defcore.txt9
-rwxr-xr-xfunctest/opnfv_tests/openstack/refstack_client/refstack_client.py23
-rwxr-xr-xfunctest/opnfv_tests/openstack/refstack_client/tempest_conf.py5
-rw-r--r--functest/opnfv_tests/openstack/snaps/health_check.py7
-rw-r--r--functest/opnfv_tests/openstack/snaps/smoke.py10
-rw-r--r--functest/opnfv_tests/openstack/snaps/snaps_test_runner.py7
-rw-r--r--functest/opnfv_tests/openstack/tempest/conf_utils.py15
-rw-r--r--functest/opnfv_tests/openstack/tempest/tempest.py22
-rw-r--r--functest/opnfv_tests/openstack/vping/vping_base.py411
-rwxr-xr-xfunctest/opnfv_tests/openstack/vping/vping_ssh.py277
-rwxr-xr-xfunctest/opnfv_tests/openstack/vping/vping_userdata.py133
-rwxr-xr-xfunctest/opnfv_tests/sdn/odl/odl.py52
-rw-r--r--functest/opnfv_tests/sdn/onos/onos.py6
-rwxr-xr-xfunctest/opnfv_tests/sdn/onos/sfc/sfc.py7
-rw-r--r--functest/opnfv_tests/sdn/onos/sfc/sfc_onos.py5
-rw-r--r--functest/opnfv_tests/sdn/onos/teston/adapters/client.py4
-rw-r--r--functest/opnfv_tests/sdn/onos/teston/adapters/connection.py4
-rw-r--r--functest/opnfv_tests/sdn/onos/teston/adapters/environment.py4
-rwxr-xr-xfunctest/opnfv_tests/vnf/aaa/aaa.py9
-rw-r--r--functest/opnfv_tests/vnf/ims/clearwater_ims_base.py8
-rw-r--r--functest/opnfv_tests/vnf/ims/cloudify_ims.py4
-rw-r--r--functest/opnfv_tests/vnf/ims/opera_ims.py24
-rwxr-xr-xfunctest/opnfv_tests/vnf/ims/orchestra_ims.py11
-rw-r--r--functest/opnfv_tests/vnf/ims/orchestrator_cloudify.py5
-rw-r--r--functest/tests/unit/ci/test_generate_report.py129
-rw-r--r--functest/tests/unit/ci/test_prepare_env.py87
-rw-r--r--functest/tests/unit/ci/test_run_tests.py42
-rw-r--r--functest/tests/unit/ci/test_tier_builder.py8
-rw-r--r--functest/tests/unit/ci/test_tier_handler.py5
-rw-r--r--functest/tests/unit/cli/commands/test_cli_env.py21
-rw-r--r--functest/tests/unit/cli/commands/test_cli_os.py33
-rw-r--r--functest/tests/unit/cli/commands/test_cli_testcase.py16
-rw-r--r--functest/tests/unit/cli/commands/test_cli_tier.py20
-rw-r--r--functest/tests/unit/core/test_feature.py2
-rw-r--r--functest/tests/unit/core/test_pytest_suite_runner.py51
-rw-r--r--functest/tests/unit/core/test_testcase.py83
-rw-r--r--functest/tests/unit/core/test_vnf.py168
-rw-r--r--functest/tests/unit/core/test_vnf_base.py52
-rw-r--r--functest/tests/unit/energy/__init__.py0
-rw-r--r--functest/tests/unit/energy/test_functest_energy.py277
-rw-r--r--functest/tests/unit/odl/test_odl.py59
-rw-r--r--functest/tests/unit/openstack/rally/test_rally.py13
-rw-r--r--functest/tests/unit/openstack/tempest/test_tempest.py18
-rw-r--r--functest/tests/unit/utils/test_decorators.py135
-rw-r--r--functest/tests/unit/utils/test_functest_logger.py48
-rw-r--r--functest/tests/unit/utils/test_functest_utils.py50
-rw-r--r--functest/tests/unit/utils/test_openstack_utils.py50
-rw-r--r--[-rwxr-xr-x]functest/utils/config.py14
-rw-r--r--[-rwxr-xr-x]functest/utils/constants.py19
-rw-r--r--functest/utils/decorators.py8
-rw-r--r--functest/utils/env.py9
-rw-r--r--functest/utils/functest_logger.py83
-rw-r--r--functest/utils/functest_utils.py26
-rw-r--r--functest/utils/openstack/cinder.py7
-rw-r--r--functest/utils/openstack/glance.py7
-rw-r--r--functest/utils/openstack/keystone.py7
-rw-r--r--functest/utils/openstack/neutron.py7
-rw-r--r--functest/utils/openstack/nova.py7
-rwxr-xr-xfunctest/utils/openstack_clean.py5
-rwxr-xr-xfunctest/utils/openstack_snapshot.py5
-rw-r--r--functest/utils/openstack_tacker.py4
-rw-r--r--functest/utils/openstack_utils.py135
-rw-r--r--requirements.txt15
-rwxr-xr-xrun_unit_tests.sh5
-rw-r--r--test-requirements.txt18
104 files changed, 7913 insertions, 1782 deletions
diff --git a/INFO b/INFO
index 6f8963e76..c38b3c62c 100644
--- a/INFO
+++ b/INFO
@@ -11,19 +11,24 @@ IRC: Server:freenode.net Channel:#opnfv-functest
Repository: functest
Committers:
-yaohelan@huawei.com
-feng.xiaowei@zte.com.cn
-ollivier.cedric@gmail.com
-jose.lausuch@ericsson.com
-morgan.richomme@orange.com
-meimei@huawei.com
-valentin.boucher@orange.com
-lanqinglong@huawei.com
-viktor.tikkanen@nokia.com
-juha.kosonen@nokia.com
-zhanghaoyu7@huawei.com
-raghavendrachari.kamsali@hpe.com
-lixiaoguang5@huawei.com
+Morgan Richomme <morgan.richomme@orange.com>
+Jose Lausuch <jose.lausuch@ericsson.com>
+Cedric Ollivier <ollivier.cedric@gmail.com>
+Helen Yao <yaohelan@huawei.com>
+Serena Feng <feng.xiaowei@zte.com.cn>
+Juha Kosonen <juha.kosonen@nokia.com>
+Valentin Boucher <valentin.boucher@orange.com>
+Viktor Tikkanen <viktor.tikkanen@nokia.com>
+Mei Mei <meimei@huawei.com>
+
+Additional contributors:
+Linda Wang <wangwulin@huawei.com>
+Georgios Paraskevopoulos <georgepar.91@gmail.com>
+Romanos Skiadas <rom.skiad@gmail.com>
+Michael Polenchuk <mpolenchuk@mirantis.com>
+Cristina Pauna <cristina.pauna@enea.com>
+Matthew Li <matthew.lijun@huawei.com>
+Steven Pisarski <s.pisarski@cablelabs.com>
Link to TSC approval of the project: http://meetbot.opnfv.org/meetings/opnfv-meeting/2015/opnfv-meeting.2015-01-20-14.57.html
diff --git a/docker/Dockerfile b/docker/Dockerfile
index 6137cc949..202eb5cb3 100644
--- a/docker/Dockerfile
+++ b/docker/Dockerfile
@@ -25,6 +25,7 @@ ARG REPOS_DIR=/home/opnfv/repos
ARG FUNCTEST_BASE_DIR=/home/opnfv/functest
ARG FUNCTEST_CONF_DIR=${FUNCTEST_BASE_DIR}/conf
ARG FUNCTEST_DATA_DIR=${FUNCTEST_BASE_DIR}/data
+ARG FUNCTEST_IMAGES_DIR=${FUNCTEST_BASE_DIR}/images
ARG FUNCTEST_RESULTS_DIR=${FUNCTEST_BASE_DIR}/results
ARG FUNCTEST_REPO_DIR=${REPOS_DIR}/functest
ARG FUNCTEST_TEST_DIR=${FUNCTEST_REPO_DIR}/functest/opnfv_tests
@@ -71,7 +72,9 @@ RUN pip install --upgrade pip
RUN mkdir -p ${REPOS_DIR} \
&& mkdir -p ${REPOS_VNFS_DIR} \
&& mkdir -p ${FUNCTEST_BASE_DIR}/results \
- && mkdir -p ${FUNCTEST_BASE_DIR}/conf \
+ && mkdir -p ${FUNCTEST_CONF_DIR} \
+ && mkdir -p ${FUNCTEST_DATA_DIR} \
+ && mkdir -p ${FUNCTEST_IMAGES_DIR} \
&& mkdir -p /root/.ssh \
&& chmod 700 /root/.ssh
diff --git a/docker/Dockerfile.aarch64 b/docker/Dockerfile.aarch64
index 83df2d0cb..b03c6d978 100644
--- a/docker/Dockerfile.aarch64
+++ b/docker/Dockerfile.aarch64
@@ -24,6 +24,7 @@ ARG REPOS_DIR=/home/opnfv/repos
ARG FUNCTEST_BASE_DIR=/home/opnfv/functest
ARG FUNCTEST_CONF_DIR=${FUNCTEST_BASE_DIR}/conf
ARG FUNCTEST_DATA_DIR=${FUNCTEST_BASE_DIR}/data
+ARG FUNCTEST_IMAGES_DIR=${FUNCTEST_BASE_DIR}/images
ARG FUNCTEST_RESULTS_DIR=${FUNCTEST_BASE_DIR}/results
ARG FUNCTEST_REPO_DIR=${REPOS_DIR}/functest
ARG FUNCTEST_TEST_DIR=${FUNCTEST_REPO_DIR}/functest/opnfv_tests
@@ -71,6 +72,8 @@ RUN mkdir -p ${REPOS_DIR} \
&& mkdir -p ${REPOS_VNFS_DIR} \
&& mkdir -p ${FUNCTEST_BASE_DIR}/results \
&& mkdir -p ${FUNCTEST_BASE_DIR}/conf \
+ && mkdir -p ${FUNCTEST_DATA_DIR} \
+ && mkdir -p ${FUNCTEST_IMAGES_DIR} \
&& mkdir -p /root/.ssh \
&& chmod 700 /root/.ssh
diff --git a/docker/add_images.sh b/docker/add_images.sh
index af2956c29..919cecd8f 100755
--- a/docker/add_images.sh
+++ b/docker/add_images.sh
@@ -7,11 +7,10 @@ CIRROS_REPO_URL=http://download.cirros-cloud.net
CIRROS_AARCH64_TAG=161201
CIRROS_X86_64_TAG=0.3.5
-wget ${CIRROS_REPO_URL}/${CIRROS_X86_64_TAG}/cirros-${CIRROS_X86_64_TAG}-x86_64-disk.img -P ${FUNCTEST_BASE_DIR}/data/
-wget ${CIRROS_REPO_URL}/${CIRROS_X86_64_TAG}/cirros-${CIRROS_X86_64_TAG}-x86_64-lxc.tar.gz -P ${FUNCTEST_BASE_DIR}/data/
-wget http://205.177.226.237:9999/onosfw/firewall_block_image.img -P ${FUNCTEST_BASE_DIR}/data/
+wget ${CIRROS_REPO_URL}/${CIRROS_X86_64_TAG}/cirros-${CIRROS_X86_64_TAG}-x86_64-disk.img -P ${FUNCTEST_IMAGES_DIR}
+wget ${CIRROS_REPO_URL}/${CIRROS_X86_64_TAG}/cirros-${CIRROS_X86_64_TAG}-x86_64-lxc.tar.gz -P ${FUNCTEST_IMAGES_DIR}
# Add the 3-part image for aarch64, since functest can be run from an x86 machine to test an aarch64 POD
-wget ${CIRROS_REPO_URL}/daily/20${CIRROS_AARCH64_TAG}/cirros-d${CIRROS_AARCH64_TAG}-aarch64-disk.img -P ${FUNCTEST_BASE_DIR}/data/
-wget ${CIRROS_REPO_URL}/daily/20${CIRROS_AARCH64_TAG}/cirros-d${CIRROS_AARCH64_TAG}-aarch64-initramfs -P ${FUNCTEST_BASE_DIR}/data/
-wget ${CIRROS_REPO_URL}/daily/20${CIRROS_AARCH64_TAG}/cirros-d${CIRROS_AARCH64_TAG}-aarch64-kernel -P ${FUNCTEST_BASE_DIR}/data/
+wget ${CIRROS_REPO_URL}/daily/20${CIRROS_AARCH64_TAG}/cirros-d${CIRROS_AARCH64_TAG}-aarch64-disk.img -P ${FUNCTEST_IMAGES_DIR}
+wget ${CIRROS_REPO_URL}/daily/20${CIRROS_AARCH64_TAG}/cirros-d${CIRROS_AARCH64_TAG}-aarch64-initramfs -P ${FUNCTEST_IMAGES_DIR}
+wget ${CIRROS_REPO_URL}/daily/20${CIRROS_AARCH64_TAG}/cirros-d${CIRROS_AARCH64_TAG}-aarch64-kernel -P ${FUNCTEST_IMAGES_DIR}
diff --git a/docs/com/pres/framework/framework.html b/docs/com/pres/framework/framework.html
new file mode 100644
index 000000000..950c2bebf
--- /dev/null
+++ b/docs/com/pres/framework/framework.html
@@ -0,0 +1,52 @@
+<html>
+<head>
+<title>OPNFV Functest Framework</title>
+<meta name="author" content="Cédric Ollivier">
+<meta name="viewport"
+ content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=no">
+<link rel="stylesheet" href="../reveal.js/css/reveal.css">
+<link rel="stylesheet" href="../reveal.js/css/theme/white.css">
+<link rel="stylesheet" href="../reveal.js/lib/css/zenburn.css">
+<script>
+var link = document.createElement( 'link' );
+link.rel = 'stylesheet';
+link.type = 'text/css';
+link.href = window.location.search.match( /print-pdf/gi ) ? '../reveal.js/css/print/pdf.css' : '../reveal.js/css/print/paper.css';
+document.getElementsByTagName( 'head' )[0].appendChild( link );
+</script>
+</head>
+<body>
+ <div class="reveal">
+ <div class="slides">
+ <section data-markdown="framework.md" data-separator="^\n\n\n"
+ data-separator-vertical="^\n\n" data-separator-notes="^Note:"></section>
+ </div>
+ </div>
+ <script src="../reveal.js/lib/js/head.min.js"></script>
+ <script src="../reveal.js/js/reveal.js"></script>
+ <script>
+ Reveal.initialize({
+ dependencies : [ {
+ src : '../reveal.js/plugin/markdown/marked.js',
+ condition : function() {
+ return !!document.querySelector('[data-markdown]');
+ }
+ }, {
+ src : '../reveal.js/plugin/markdown/markdown.js',
+ condition : function() {
+ return !!document.querySelector('[data-markdown]');
+ }
+ }, {
+ src: '../reveal.js/plugin/highlight/highlight.js',
+ async: true,
+ callback: function() {
+ hljs.initHighlightingOnLoad();
+ }
+ }, {
+ src: '../reveal.js/plugin/notes/notes.js',
+ async: true
+ } ]
+ });
+ </script>
+</body>
+</html>
diff --git a/docs/com/pres/framework/framework.md b/docs/com/pres/framework/framework.md
new file mode 100644
index 000000000..3c1aae1b8
--- /dev/null
+++ b/docs/com/pres/framework/framework.md
@@ -0,0 +1,268 @@
+# Functest Framework
+
+created by [Cédric Ollivier](mailto:cedric.ollivier@orange.com)
+
+2017/05/06
+
+Note:
+
+- Functest integrates lots of heterogeneous testcases:
+ - python vs bash
+ - internal vs external
+- it aims to benefit from object programming
+ - to define common operations
+ - to avoid conditional instructions regarding the testcases
+ - to avoid duplicating code
+ - to ease the integration of third-party testcases (written in Bash or Python)
+
+
+
+## Quick overview
+
+
+### Functest function calls
+
+- **CI** calls *run_tests.py* (please see [jenkins jobs](https://gerrit.opnfv.org/gerrit/gitweb?p=releng.git;a=tree;f=jjb/functest))
+- *run_tests.py* parses *functest/ci/testcases.yaml* to:
+ - check which testcase(s) must be run
+ - execute the common operations on every testcase (run, push its results to db...)
+<!-- .element: class="fragment highlight-red"-->
+ - return the right status code to **CI**
+
+
+### Our target
+
+- limit run_tests.py instructions by defining:
+ - the basic testcase attributes
+ - all common operations
+ - the status codes expected
+- avoid duplicating codes between testcases
+- ease the development of third-party testcases (aka features)
+
+
+
+## class TestCase
+
+base model for single test case
+
+
+### instance attributes
+
+- project_name (default: 'functest')
+- case_name
+- criteria
+- result
+- start_time
+- stop_time
+- details
+
+
+### methods
+
+| Method | Purpose |
+|-------------------|--------------------------------------------|
+| run(**kwargs) | run the test case |
+| is_successful() | interpret the results of the test case |
+| get_duration() | return the duration of the test case |
+| push_to_db() | push the results of the test case to the DB|
+
+
+### run(**kwargs)
+
+- the subclasses must override the default implementation which is false on purpose
+- the new implementation must set the following attributes to push the results to DB:
+ - result
+ - start_time
+ - stop_time
+
+
+### class attributes
+
+| Status code | Returned when |
+|--------------------|---------------------|
+| EX_OK | everything is OK |
+| EX_RUN_ERROR | run() failed |
+| EX_TESTCASE_FAILED | results are false |
+| EX_PUSH_TO_DB_ERROR| push_to_db() failed |
+
+
+### run_tests.py
+
+```python
+module = importlib.import_module(run_dict['module'])
+cls = getattr(module, run_dict['class'])
+test_dict = ft_utils.get_dict_by_test(test_name)
+test_case = cls(**test_dict)
+try:
+ kwargs = run_dict['args']
+ result = test_case.run(**kwargs)
+except KeyError:
+ result = test_case.run()
+if result == testcase.TestCase.EX_OK:
+ if GlobalVariables.REPORT_FLAG:
+ test_case.push_to_db()
+ result = test_case.is_successful()
+```
+
+
+
+## Your first test case
+
+
+### first.py
+
+```python
+#!/usr/bin/env python
+
+import time
+
+from functest.core import testcase
+
+class Test(testcase.TestCase):
+
+ def run(self, **kwargs):
+ self.start_time = time.time()
+ print "Hello World"
+ self.result = 100
+ self.stop_time = time.time()
+ return testcase.TestCase.EX_OK
+```
+
+
+### functest/ci/testcases.yaml
+
+```yaml
+case_name: first
+project_name: functest
+criteria: 100
+blocking: true
+clean_flag: false
+description: ''
+dependencies:
+ installer: ''
+ scenario: ''
+run:
+ module: 'first'
+ class: 'Test'
+```
+
+
+
+## class Feature
+bases: TestCase
+
+base model for single feature
+
+
+### methods
+
+| Method | Purpose |
+|-------------------|---------------------------|
+| run(**kwargs) | run the feature |
+| execute(**kwargs) | execute the Python method |
+
+
+### run(**kwargs)
+
+- allows executing any Python method by calling execute()
+- sets the following attributes required to push the results to DB:
+ - result
+ - start_time
+ - stop_time
+- doesn't fulfill details when pushing the results to the DB.
+
+
+### execute(**kwargs)
+
+- the subclasses must override the default implementation which is false on purpose
+- the new implementation must return 0 if success or anything else if failure.
+
+
+
+## Your second test case
+
+
+### second.py
+
+```python
+#!/usr/bin/env python
+
+from functest.core import feature
+
+class Test(feature.Feature):
+
+ def execute(self, **kwargs):
+ print "Hello World"
+ return 0
+```
+
+
+### functest/ci/testcases.yaml
+
+```yaml
+case_name: second
+project_name: functest
+criteria: 100
+blocking: true
+clean_flag: false
+description: ''
+dependencies:
+ installer: ''
+ scenario: ''
+run:
+ module: 'second'
+ class: 'Test'
+```
+
+
+
+## class BashFeature
+bases: Feature
+
+class designed to run any bash command
+
+
+### execute(**kwargs)
+
+execute the cmd passed as arg.
+
+
+
+## Your third test case
+
+
+### functest/ci/testcases.yaml
+
+```
+case_name: third
+project_name: functest
+criteria: 100
+blocking: true
+clean_flag: false
+description: ''
+dependencies:
+ installer: ''
+ scenario: ''
+run:
+ module: 'functest.core.feature'
+ class: 'BashFeature'
+ args:
+ cmd: 'echo Hello World; exit 0'
+```
+
+
+
+## Euphrates
+
+
+### Next actions
+
+- __to finish VNF abstraction (coverage + pylint)__
+- to publish doc API
+- to manage criteria as written in testcases.yaml
+
+Please see [Functest Euphrates page](https://wiki.opnfv.org/display/functest/Functest+Euphrates+page) for more details
+
+
+
+## Thank You!
diff --git a/docs/results/danube/2.0/apex.html b/docs/results/danube/2.0/apex.html
new file mode 100644
index 000000000..4460087e2
--- /dev/null
+++ b/docs/results/danube/2.0/apex.html
@@ -0,0 +1,1057 @@
+ <html>
+ <head>
+ <meta charset="utf-8">
+ <!-- Bootstrap core CSS -->
+ <link href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.4/css/bootstrap.min.css" rel="stylesheet">
+ <link href="../../js/default.css" rel="stylesheet">
+ <script type="text/javascript" src="http://ajax.googleapis.com/ajax/libs/jquery/1/jquery.min.js"></script>
+ <script type="text/javascript" src="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.4/js/bootstrap.min.js"></script>
+ <script type="text/javascript" src="http://d3js.org/d3.v2.min.js"></script>
+ <script type="text/javascript" src="../../js/gauge.js"></script>
+ <script type="text/javascript" src="../../js/trend.js"></script>
+ <script>
+ function onDocumentReady() {
+ // Gauge management
+ var gaugeScenario1 = gauge('#gaugeScenario1');var gaugeScenario2 = gauge('#gaugeScenario2');var gaugeScenario3 = gauge('#gaugeScenario3');var gaugeScenario4 = gauge('#gaugeScenario4');var gaugeScenario5 = gauge('#gaugeScenario5');var gaugeScenario6 = gauge('#gaugeScenario6');var gaugeScenario7 = gauge('#gaugeScenario7');var gaugeScenario8 = gauge('#gaugeScenario8');var gaugeScenario9 = gauge('#gaugeScenario9');var gaugeScenario10 = gauge('#gaugeScenario10');var gaugeScenario11 = gauge('#gaugeScenario11');var gaugeScenario12 = gauge('#gaugeScenario12');var gaugeScenario13 = gauge('#gaugeScenario13');var gaugeScenario14 = gauge('#gaugeScenario14');
+
+ // assign success rate to the gauge
+ function updateReadings() {
+ gaugeScenario1.update(93.3333333333);gaugeScenario2.update(50.0);gaugeScenario3.update(27.2727272727);gaugeScenario4.update(77.7777777778);gaugeScenario5.update(18.1818181818);gaugeScenario6.update(44.4444444444);gaugeScenario7.update(90.9090909091);gaugeScenario8.update(76.6666666667);gaugeScenario9.update(20.0);gaugeScenario10.update(69.696969697);gaugeScenario11.update(18.1818181818);gaugeScenario12.update(80.5555555556);gaugeScenario13.update(90.9090909091);gaugeScenario14.update(76.6666666667);
+ }
+ updateReadings();
+ }
+
+ // trend line management
+ d3.csv("./scenario_history.txt", function(data) {
+ // ***************************************
+ // Create the trend line
+ // for scenario os-nosdn-fdio-noha
+ // Filter results
+ var trend1 = data.filter(function(row) {
+ return row["scenario"]=="os-nosdn-fdio-noha" && row["installer"]=="apex";
+ })
+ // Parse the date
+ trend1.forEach(function(d) {
+ d.date = parseDate(d.date);
+ d.score = +d.score
+ });
+ // Draw the trend line
+ var mytrend = trend("#trend_svg1",trend1)
+ // ****************************************// for scenario os-odl-gluon-noha
+ // Filter results
+ var trend2 = data.filter(function(row) {
+ return row["scenario"]=="os-odl-gluon-noha" && row["installer"]=="apex";
+ })
+ // Parse the date
+ trend2.forEach(function(d) {
+ d.date = parseDate(d.date);
+ d.score = +d.score
+ });
+ // Draw the trend line
+ var mytrend = trend("#trend_svg2",trend2)
+ // ****************************************// for scenario os-ovn-nofeature-noha
+ // Filter results
+ var trend3 = data.filter(function(row) {
+ return row["scenario"]=="os-ovn-nofeature-noha" && row["installer"]=="apex";
+ })
+ // Parse the date
+ trend3.forEach(function(d) {
+ d.date = parseDate(d.date);
+ d.score = +d.score
+ });
+ // Draw the trend line
+ var mytrend = trend("#trend_svg3",trend3)
+ // ****************************************// for scenario os-odl_l2-fdio-noha
+ // Filter results
+ var trend4 = data.filter(function(row) {
+ return row["scenario"]=="os-odl_l2-fdio-noha" && row["installer"]=="apex";
+ })
+ // Parse the date
+ trend4.forEach(function(d) {
+ d.date = parseDate(d.date);
+ d.score = +d.score
+ });
+ // Draw the trend line
+ var mytrend = trend("#trend_svg4",trend4)
+ // ****************************************// for scenario os-odl_l3-ovs-ha
+ // Filter results
+ var trend5 = data.filter(function(row) {
+ return row["scenario"]=="os-odl_l3-ovs-ha" && row["installer"]=="apex";
+ })
+ // Parse the date
+ trend5.forEach(function(d) {
+ d.date = parseDate(d.date);
+ d.score = +d.score
+ });
+ // Draw the trend line
+ var mytrend = trend("#trend_svg5",trend5)
+ // ****************************************// for scenario os-odl-bgpvpn-ha
+ // Filter results
+ var trend6 = data.filter(function(row) {
+ return row["scenario"]=="os-odl-bgpvpn-ha" && row["installer"]=="apex";
+ })
+ // Parse the date
+ trend6.forEach(function(d) {
+ d.date = parseDate(d.date);
+ d.score = +d.score
+ });
+ // Draw the trend line
+ var mytrend = trend("#trend_svg6",trend6)
+ // ****************************************// for scenario os-nosdn-kvm-ha
+ // Filter results
+ var trend7 = data.filter(function(row) {
+ return row["scenario"]=="os-nosdn-kvm-ha" && row["installer"]=="apex";
+ })
+ // Parse the date
+ trend7.forEach(function(d) {
+ d.date = parseDate(d.date);
+ d.score = +d.score
+ });
+ // Draw the trend line
+ var mytrend = trend("#trend_svg7",trend7)
+ // ****************************************// for scenario os-odl_l3-fdio-noha
+ // Filter results
+ var trend8 = data.filter(function(row) {
+ return row["scenario"]=="os-odl_l3-fdio-noha" && row["installer"]=="apex";
+ })
+ // Parse the date
+ trend8.forEach(function(d) {
+ d.date = parseDate(d.date);
+ d.score = +d.score
+ });
+ // Draw the trend line
+ var mytrend = trend("#trend_svg8",trend8)
+ // ****************************************// for scenario os-nosdn-fdio-ha
+ // Filter results
+ var trend9 = data.filter(function(row) {
+ return row["scenario"]=="os-nosdn-fdio-ha" && row["installer"]=="apex";
+ })
+ // Parse the date
+ trend9.forEach(function(d) {
+ d.date = parseDate(d.date);
+ d.score = +d.score
+ });
+ // Draw the trend line
+ var mytrend = trend("#trend_svg9",trend9)
+ // ****************************************// for scenario os-odl_l3-nofeature-ha
+ // Filter results
+ var trend10 = data.filter(function(row) {
+ return row["scenario"]=="os-odl_l3-nofeature-ha" && row["installer"]=="apex";
+ })
+ // Parse the date
+ trend10.forEach(function(d) {
+ d.date = parseDate(d.date);
+ d.score = +d.score
+ });
+ // Draw the trend line
+ var mytrend = trend("#trend_svg10",trend10)
+ // ****************************************// for scenario os-nosdn-ovs-ha
+ // Filter results
+ var trend11 = data.filter(function(row) {
+ return row["scenario"]=="os-nosdn-ovs-ha" && row["installer"]=="apex";
+ })
+ // Parse the date
+ trend11.forEach(function(d) {
+ d.date = parseDate(d.date);
+ d.score = +d.score
+ });
+ // Draw the trend line
+ var mytrend = trend("#trend_svg11",trend11)
+ // ****************************************// for scenario os-odl_l2-fdio-ha
+ // Filter results
+ var trend12 = data.filter(function(row) {
+ return row["scenario"]=="os-odl_l2-fdio-ha" && row["installer"]=="apex";
+ })
+ // Parse the date
+ trend12.forEach(function(d) {
+ d.date = parseDate(d.date);
+ d.score = +d.score
+ });
+ // Draw the trend line
+ var mytrend = trend("#trend_svg12",trend12)
+ // ****************************************// for scenario os-nosdn-nofeature-ha
+ // Filter results
+ var trend13 = data.filter(function(row) {
+ return row["scenario"]=="os-nosdn-nofeature-ha" && row["installer"]=="apex";
+ })
+ // Parse the date
+ trend13.forEach(function(d) {
+ d.date = parseDate(d.date);
+ d.score = +d.score
+ });
+ // Draw the trend line
+ var mytrend = trend("#trend_svg13",trend13)
+ // ****************************************// for scenario os-odl_l3-fdio-ha
+ // Filter results
+ var trend14 = data.filter(function(row) {
+ return row["scenario"]=="os-odl_l3-fdio-ha" && row["installer"]=="apex";
+ })
+ // Parse the date
+ trend14.forEach(function(d) {
+ d.date = parseDate(d.date);
+ d.score = +d.score
+ });
+ // Draw the trend line
+ var mytrend = trend("#trend_svg14",trend14)
+ // ****************************************
+ });
+ if ( !window.isLoaded ) {
+ window.addEventListener("load", function() {
+ onDocumentReady();
+ }, false);
+ } else {
+ onDocumentReady();
+ }
+</script>
+<script type="text/javascript">
+$(document).ready(function (){
+ $(".btn-more").click(function() {
+ $(this).hide();
+ $(this).parent().find(".panel-default").show();
+ });
+})
+</script>
+
+ </head>
+ <body>
+ <div class="container">
+ <div class="masthead">
+ <h3 class="text-muted">Functest status page (danube, 2017-05-05 01:45)</h3>
+ <nav>
+ <ul class="nav nav-justified">
+ <li class="active"><a href="http://testresults.opnfv.org/reporting/index.html">Home</a></li>
+ <li><a href="apex.html">Apex</a></li>
+ <li><a href="compass.html">Compass</a></li>
+ <li><a href="fuel.html">Fuel</a></li>
+ <li><a href="joid.html">Joid</a></li>
+ </ul>
+ </nav>
+ </div>
+<div class="row">
+ <div class="col-md-1"></div>
+ <div class="col-md-10">
+ <div class="page-header">
+ <h2>apex</h2>
+ </div>
+
+ <div class="scenario-overview">
+ <div class="panel-heading"><h4><b>List of last scenarios (danube) run over the last 10 days </b></h4></div>
+ <table class="table">
+ <tr>
+ <th width="40%">Scenario</th>
+ <th width="20%">Status</th>
+ <th width="20%">Trend</th>
+ <th width="10%">Score</th>
+ <th width="10%">Iteration</th>
+ </tr>
+ <tr class="tr-ok">
+ <td><a href=http://testresultS.opnfv.org/reporting>os-nosdn-fdio-noha</a></td>
+ <td><div id="gaugeScenario1"></div></td>
+ <td><div id="trend_svg1"></div></td>
+ <td>28/30</td>
+ <td>10</td>
+ </tr><tr class="tr-ok">
+ <td><a href=https://build.opnfv.org/ci/view/functest/job/functest-apex-apex-daily-danube-daily-danube/225/console>os-odl-gluon-noha</a></td>
+ <td><div id="gaugeScenario2"></div></td>
+ <td><div id="trend_svg2"></div></td>
+ <td>18/36</td>
+ <td>3</td>
+ </tr><tr class="tr-ok">
+ <td><a href=https://build.opnfv.org/ci/view/functest/job/functest-apex-apex-daily-danube-daily-danube/221/console>os-ovn-nofeature-noha</a></td>
+ <td><div id="gaugeScenario3"></div></td>
+ <td><div id="trend_svg3"></div></td>
+ <td>9/33</td>
+ <td>5</td>
+ </tr><tr class="tr-ok">
+ <td><a href=https://build.opnfv.org/ci/view/functest/job/functest-apex-apex-daily-danube-daily-danube/226/console>os-odl_l2-fdio-noha</a></td>
+ <td><div id="gaugeScenario4"></div></td>
+ <td><div id="trend_svg4"></div></td>
+ <td>28/36</td>
+ <td>6</td>
+ </tr><tr class="tr-ok">
+ <td><a href=https://build.opnfv.org/ci/view/functest/job/functest-apex-apex-daily-danube-daily-danube/220/console>os-odl_l3-ovs-ha</a></td>
+ <td><div id="gaugeScenario5"></div></td>
+ <td><div id="trend_svg5"></div></td>
+ <td>6/33</td>
+ <td>4</td>
+ </tr><tr class="tr-ok">
+ <td><a href=https://build.opnfv.org/ci/view/functest/job/functest-apex-apex-daily-danube-daily-danube/224/console>os-odl-bgpvpn-ha</a></td>
+ <td><div id="gaugeScenario6"></div></td>
+ <td><div id="trend_svg6"></div></td>
+ <td>16/36</td>
+ <td>3</td>
+ </tr><tr class="tr-ok">
+ <td><a href=https://build.opnfv.org/ci/view/functest/job/functest-apex-apex-daily-danube-daily-danube/228/console>os-nosdn-kvm-ha</a></td>
+ <td><div id="gaugeScenario7"></div></td>
+ <td><div id="trend_svg7"></div></td>
+ <td>30/33</td>
+ <td>6</td>
+ </tr><tr class="tr-ok">
+ <td><a href=https://build.opnfv.org/ci/view/functest/job/functest-apex-apex-daily-danube-daily-danube/217/console>os-odl_l3-fdio-noha</a></td>
+ <td><div id="gaugeScenario8"></div></td>
+ <td><div id="trend_svg8"></div></td>
+ <td>23/30</td>
+ <td>13</td>
+ </tr><tr class="tr-ok">
+ <td><a href=https://build.opnfv.org/ci/view/functest/job/functest-apex-apex-daily-danube-daily-danube/230/console>os-nosdn-fdio-ha</a></td>
+ <td><div id="gaugeScenario9"></div></td>
+ <td><div id="trend_svg9"></div></td>
+ <td>6/30</td>
+ <td>6</td>
+ </tr><tr class="tr-ok">
+ <td><a href=https://build.opnfv.org/ci/view/functest/job/functest-apex-apex-daily-danube-daily-danube/211/console>os-odl_l3-nofeature-ha</a></td>
+ <td><div id="gaugeScenario10"></div></td>
+ <td><div id="trend_svg10"></div></td>
+ <td>23/33</td>
+ <td>5</td>
+ </tr><tr class="tr-ok">
+ <td><a href=https://build.opnfv.org/ci/view/functest/job/functest-apex-apex-daily-danube-daily-danube/231/console>os-nosdn-ovs-ha</a></td>
+ <td><div id="gaugeScenario11"></div></td>
+ <td><div id="trend_svg11"></div></td>
+ <td>6/33</td>
+ <td>6</td>
+ </tr><tr class="tr-ok">
+ <td><a href=https://build.opnfv.org/ci/view/functest/job/functest-apex-apex-daily-danube-daily-danube/227/console>os-odl_l2-fdio-ha</a></td>
+ <td><div id="gaugeScenario12"></div></td>
+ <td><div id="trend_svg12"></div></td>
+ <td>29/36</td>
+ <td>20</td>
+ </tr><tr class="tr-ok">
+ <td><a href=https://build.opnfv.org/ci/view/functest/job/functest-apex-apex-daily-danube-daily-danube/222/console>os-nosdn-nofeature-ha</a></td>
+ <td><div id="gaugeScenario13"></div></td>
+ <td><div id="trend_svg13"></div></td>
+ <td>30/33</td>
+ <td>5</td>
+ </tr><tr class="tr-ok">
+ <td><a href=https://build.opnfv.org/ci/view/functest/job/functest-apex-apex-daily-danube-daily-danube/229/console>os-odl_l3-fdio-ha</a></td>
+ <td><div id="gaugeScenario14"></div></td>
+ <td><div id="trend_svg14"></div></td>
+ <td>23/30</td>
+ <td>6</td>
+ </tr>
+ </table>
+ </div>
+
+
+ <div class="scenario-part">
+ <div class="page-header">
+ <h3><span class="glyphicon glyphicon-chevron-right"> <b>os-nosdn-fdio-noha</b></h3>
+ </div>
+ <div class="panel panel-default">
+ <div class="panel-heading">
+ <span class="panel-header-item">
+ </span>
+ </div>
+ <table class="table">
+ <tr>
+ <th>
+ Health (connection)
+
+ </th><th>
+ Health (api)
+
+ </th><th>
+ Health (dhcp)
+
+ </th><th>
+ vPing (ssh)
+
+ </th><th>
+ vPing (userdata)
+
+ </th><th>
+ Tempest (smoke)
+
+ </th><th>
+ Rally (smoke)
+
+ </th><th>
+ Refstack
+
+ </th><th>
+ SNAPS
+
+ </th><th>
+ Domino
+
+ </th>
+ </tr>
+ <tr class="tr-weather-weather">
+ <td><img src="../../img/weather-clear.png"></td><td><img src="../../img/weather-clear.png"></td><td><img src="../../img/weather-clear.png"></td><td><img src="../../img/weather-clear.png"></td><td><img src="../../img/weather-clear.png"></td><td><img src="../../img/weather-few-clouds.png"></td><td><img src="../../img/weather-clear.png"></td><td><img src="../../img/weather-clear.png"></td><td><img src="../../img/weather-few-clouds.png"></td><td><img src="../../img/weather-clear.png"></td>
+ </tr>
+ </table>
+ </div>
+ </div><div class="scenario-part">
+ <div class="page-header">
+ <h3><span class="glyphicon glyphicon-chevron-right"> <b>os-odl-gluon-noha</b></h3>
+ </div>
+ <div class="panel panel-default">
+ <div class="panel-heading">
+ <span class="panel-header-item">
+ </span>
+ </div>
+ <table class="table">
+ <tr>
+ <th>
+ Health (connection)
+
+ </th><th>
+ Health (api)
+
+ </th><th>
+ Health (dhcp)
+
+ </th><th>
+ vPing (userdata)
+
+ </th><th>
+ Tempest (smoke)
+
+ </th><th>
+ Rally (smoke)
+
+ </th><th>
+ Refstack
+
+ </th><th>
+ ODL
+
+ </th><th>
+ SNAPS
+
+ </th><th>
+ Doctor
+
+ </th><th>
+ Domino
+
+ </th><th>
+ Netready
+
+ </th>
+ </tr>
+ <tr class="tr-weather-weather">
+ <td><img src="../../img/weather-few-clouds.png"></td><td><img src="../../img/weather-few-clouds.png"></td><td><img src="../../img/weather-few-clouds.png"></td><td><img src="../../img/weather-few-clouds.png"></td><td><img src="../../img/weather-storm.png"></td><td><img src="../../img/weather-few-clouds.png"></td><td><img src="../../img/weather-storm.png"></td><td><img src="../../img/weather-few-clouds.png"></td><td><img src="../../img/weather-few-clouds.png"></td><td><img src="../../img/weather-few-clouds.png"></td><td><img src="../../img/weather-storm.png"></td><td><img src="../../img/weather-few-clouds.png"></td>
+ </tr>
+ </table>
+ </div>
+ </div><div class="scenario-part">
+ <div class="page-header">
+ <h3><span class="glyphicon glyphicon-chevron-right"> <b>os-ovn-nofeature-noha</b></h3>
+ </div>
+ <div class="panel panel-default">
+ <div class="panel-heading">
+ <span class="panel-header-item">
+ </span>
+ </div>
+ <table class="table">
+ <tr>
+ <th>
+ Health (connection)
+
+ </th><th>
+ Health (api)
+
+ </th><th>
+ Health (dhcp)
+
+ </th><th>
+ vPing (ssh)
+
+ </th><th>
+ vPing (userdata)
+
+ </th><th>
+ Tempest (smoke)
+
+ </th><th>
+ Rally (smoke)
+
+ </th><th>
+ Refstack
+
+ </th><th>
+ SNAPS
+
+ </th><th>
+ Doctor
+
+ </th><th>
+ Domino
+
+ </th>
+ </tr>
+ <tr class="tr-weather-weather">
+ <td><img src="../../img/weather-clear.png"></td><td><img src="../../img/weather-clear.png"></td><td><img src="../../img/weather-clear.png"></td><td><img src="../../img/weather-storm.png"></td><td><img src="../../img/weather-storm.png"></td><td><img src="../../img/weather-storm.png"></td><td><img src="../../img/weather-storm.png"></td><td><img src="../../img/weather-storm.png"></td><td><img src="../../img/weather-storm.png"></td><td><img src="../../img/weather-storm.png"></td><td><img src="../../img/weather-storm.png"></td>
+ </tr>
+ </table>
+ </div>
+ </div><div class="scenario-part">
+ <div class="page-header">
+ <h3><span class="glyphicon glyphicon-chevron-right"> <b>os-odl_l2-fdio-noha</b></h3>
+ </div>
+ <div class="panel panel-default">
+ <div class="panel-heading">
+ <span class="panel-header-item">
+ </span>
+ </div>
+ <table class="table">
+ <tr>
+ <th>
+ Health (connection)
+
+ </th><th>
+ Health (api)
+
+ </th><th>
+ Health (dhcp)
+
+ </th><th>
+ vPing (ssh)
+
+ </th><th>
+ vPing (userdata)
+
+ </th><th>
+ Tempest (smoke)
+
+ </th><th>
+ Rally (smoke)
+
+ </th><th>
+ Refstack
+
+ </th><th>
+ ODL
+
+ </th><th>
+ FDS
+
+ </th><th>
+ SNAPS
+
+ </th><th>
+ Domino
+
+ </th>
+ </tr>
+ <tr class="tr-weather-weather">
+ <td><img src="../../img/weather-clear.png"></td><td><img src="../../img/weather-clear.png"></td><td><img src="../../img/weather-clear.png"></td><td><img src="../../img/weather-clear.png"></td><td><img src="../../img/weather-clear.png"></td><td><img src="../../img/weather-clear.png"></td><td><img src="../../img/weather-clear.png"></td><td><img src="../../img/weather-few-clouds.png"></td><td><img src="../../img/weather-clear.png"></td><td><img src="../../img/weather-storm.png"></td><td><img src="../../img/weather-few-clouds.png"></td><td><img src="../../img/weather-storm.png"></td>
+ </tr>
+ </table>
+ </div>
+ </div><div class="scenario-part">
+ <div class="page-header">
+ <h3><span class="glyphicon glyphicon-chevron-right"> <b>os-odl_l3-ovs-ha</b></h3>
+ </div>
+ <div class="panel panel-default">
+ <div class="panel-heading">
+ <span class="panel-header-item">
+ </span>
+ </div>
+ <table class="table">
+ <tr>
+ <th>
+ Health (connection)
+
+ </th><th>
+ Health (api)
+
+ </th><th>
+ Health (dhcp)
+
+ </th><th>
+ vPing (userdata)
+
+ </th><th>
+ Tempest (smoke)
+
+ </th><th>
+ Rally (smoke)
+
+ </th><th>
+ Refstack
+
+ </th><th>
+ ODL
+
+ </th><th>
+ SNAPS
+
+ </th><th>
+ Doctor
+
+ </th><th>
+ Domino
+
+ </th>
+ </tr>
+ <tr class="tr-weather-weather">
+ <td><img src="../../img/weather-clear.png"></td><td><img src="../../img/weather-clear.png"></td><td><img src="../../img/weather-storm.png"></td><td><img src="../../img/weather-storm.png"></td><td><img src="../../img/weather-storm.png"></td><td><img src="../../img/weather-storm.png"></td><td><img src="../../img/weather-storm.png"></td><td><img src="../../img/weather-storm.png"></td><td><img src="../../img/weather-storm.png"></td><td><img src="../../img/weather-storm.png"></td><td><img src="../../img/weather-storm.png"></td>
+ </tr>
+ </table>
+ </div>
+ </div><div class="scenario-part">
+ <div class="page-header">
+ <h3><span class="glyphicon glyphicon-chevron-right"> <b>os-odl-bgpvpn-ha</b></h3>
+ </div>
+ <div class="panel panel-default">
+ <div class="panel-heading">
+ <span class="panel-header-item">
+ </span>
+ </div>
+ <table class="table">
+ <tr>
+ <th>
+ Health (connection)
+
+ </th><th>
+ Health (api)
+
+ </th><th>
+ Health (dhcp)
+
+ </th><th>
+ vPing (userdata)
+
+ </th><th>
+ Tempest (smoke)
+
+ </th><th>
+ Rally (smoke)
+
+ </th><th>
+ Refstack
+
+ </th><th>
+ ODL
+
+ </th><th>
+ SNAPS
+
+ </th><th>
+ Doctor
+
+ </th><th>
+ bgpvpn
+
+ </th><th>
+ Domino
+
+ </th>
+ </tr>
+ <tr class="tr-weather-weather">
+ <td><img src="../../img/weather-few-clouds.png"></td><td><img src="../../img/weather-few-clouds.png"></td><td><img src="../../img/weather-few-clouds.png"></td><td><img src="../../img/weather-few-clouds.png"></td><td><img src="../../img/weather-storm.png"></td><td><img src="../../img/weather-few-clouds.png"></td><td><img src="../../img/weather-storm.png"></td><td><img src="../../img/weather-few-clouds.png"></td><td><img src="../../img/weather-few-clouds.png"></td><td><img src="../../img/weather-few-clouds.png"></td><td><img src="../../img/weather-storm.png"></td><td><img src="../../img/weather-storm.png"></td>
+ </tr>
+ </table>
+ </div>
+ </div><div class="scenario-part">
+ <div class="page-header">
+ <h3><span class="glyphicon glyphicon-chevron-right"> <b>os-nosdn-kvm-ha</b></h3>
+ </div>
+ <div class="panel panel-default">
+ <div class="panel-heading">
+ <span class="panel-header-item">
+ </span>
+ </div>
+ <table class="table">
+ <tr>
+ <th>
+ Health (connection)
+
+ </th><th>
+ Health (api)
+
+ </th><th>
+ Health (dhcp)
+
+ </th><th>
+ vPing (ssh)
+
+ </th><th>
+ vPing (userdata)
+
+ </th><th>
+ Tempest (smoke)
+
+ </th><th>
+ Rally (smoke)
+
+ </th><th>
+ Refstack
+
+ </th><th>
+ SNAPS
+
+ </th><th>
+ Doctor
+
+ </th><th>
+ Domino
+
+ </th>
+ </tr>
+ <tr class="tr-weather-weather">
+ <td><img src="../../img/weather-clear.png"></td><td><img src="../../img/weather-clear.png"></td><td><img src="../../img/weather-clear.png"></td><td><img src="../../img/weather-clear.png"></td><td><img src="../../img/weather-clear.png"></td><td><img src="../../img/weather-clear.png"></td><td><img src="../../img/weather-clear.png"></td><td><img src="../../img/weather-clear.png"></td><td><img src="../../img/weather-clear.png"></td><td><img src="../../img/weather-clear.png"></td><td><img src="../../img/weather-storm.png"></td>
+ </tr>
+ </table>
+ </div>
+ </div><div class="scenario-part">
+ <div class="page-header">
+ <h3><span class="glyphicon glyphicon-chevron-right"> <b>os-odl_l3-fdio-noha</b></h3>
+ </div>
+ <div class="panel panel-default">
+ <div class="panel-heading">
+ <span class="panel-header-item">
+ </span>
+ </div>
+ <table class="table">
+ <tr>
+ <th>
+ Health (connection)
+
+ </th><th>
+ Health (api)
+
+ </th><th>
+ Health (dhcp)
+
+ </th><th>
+ vPing (userdata)
+
+ </th><th>
+ Tempest (smoke)
+
+ </th><th>
+ Rally (smoke)
+
+ </th><th>
+ Refstack
+
+ </th><th>
+ ODL
+
+ </th><th>
+ SNAPS
+
+ </th><th>
+ Domino
+
+ </th>
+ </tr>
+ <tr class="tr-weather-weather">
+ <td><img src="../../img/weather-clear.png"></td><td><img src="../../img/weather-clear.png"></td><td><img src="../../img/weather-few-clouds.png"></td><td><img src="../../img/weather-clear.png"></td><td><img src="../../img/weather-storm.png"></td><td><img src="../../img/weather-clear.png"></td><td><img src="../../img/weather-storm.png"></td><td><img src="../../img/weather-clear.png"></td><td><img src="../../img/weather-clear.png"></td><td><img src="../../img/weather-clear.png"></td>
+ </tr>
+ </table>
+ </div>
+ </div><div class="scenario-part">
+ <div class="page-header">
+ <h3><span class="glyphicon glyphicon-chevron-right"> <b>os-nosdn-fdio-ha</b></h3>
+ </div>
+ <div class="panel panel-default">
+ <div class="panel-heading">
+ <span class="panel-header-item">
+ </span>
+ </div>
+ <table class="table">
+ <tr>
+ <th>
+ Health (connection)
+
+ </th><th>
+ Health (api)
+
+ </th><th>
+ Health (dhcp)
+
+ </th><th>
+ vPing (ssh)
+
+ </th><th>
+ vPing (userdata)
+
+ </th><th>
+ Tempest (smoke)
+
+ </th><th>
+ Rally (smoke)
+
+ </th><th>
+ Refstack
+
+ </th><th>
+ SNAPS
+
+ </th><th>
+ Domino
+
+ </th>
+ </tr>
+ <tr class="tr-weather-weather">
+ <td><img src="../../img/weather-clear.png"></td><td><img src="../../img/weather-clear.png"></td><td><img src="../../img/weather-storm.png"></td><td><img src="../../img/weather-storm.png"></td><td><img src="../../img/weather-storm.png"></td><td><img src="../../img/weather-storm.png"></td><td><img src="../../img/weather-storm.png"></td><td><img src="../../img/weather-storm.png"></td><td><img src="../../img/weather-storm.png"></td><td><img src="../../img/weather-storm.png"></td>
+ </tr>
+ </table>
+ </div>
+ </div><div class="scenario-part">
+ <div class="page-header">
+ <h3><span class="glyphicon glyphicon-chevron-right"> <b>os-odl_l3-nofeature-ha</b></h3>
+ </div>
+ <div class="panel panel-default">
+ <div class="panel-heading">
+ <span class="panel-header-item">
+ </span>
+ </div>
+ <table class="table">
+ <tr>
+ <th>
+ Health (connection)
+
+ </th><th>
+ Health (api)
+
+ </th><th>
+ Health (dhcp)
+
+ </th><th>
+ vPing (userdata)
+
+ </th><th>
+ Tempest (smoke)
+
+ </th><th>
+ Rally (smoke)
+
+ </th><th>
+ Refstack
+
+ </th><th>
+ ODL
+
+ </th><th>
+ SNAPS
+
+ </th><th>
+ Doctor
+
+ </th><th>
+ Domino
+
+ </th>
+ </tr>
+ <tr class="tr-weather-weather">
+ <td><img src="../../img/weather-clear.png"></td><td><img src="../../img/weather-clear.png"></td><td><img src="../../img/weather-clear.png"></td><td><img src="../../img/weather-clear.png"></td><td><img src="../../img/weather-storm.png"></td><td><img src="../../img/weather-clear.png"></td><td><img src="../../img/weather-storm.png"></td><td><img src="../../img/weather-few-clouds.png"></td><td><img src="../../img/weather-clear.png"></td><td><img src="../../img/weather-clear.png"></td><td><img src="../../img/weather-storm.png"></td>
+ </tr>
+ </table>
+ </div>
+ </div><div class="scenario-part">
+ <div class="page-header">
+ <h3><span class="glyphicon glyphicon-chevron-right"> <b>os-nosdn-ovs-ha</b></h3>
+ </div>
+ <div class="panel panel-default">
+ <div class="panel-heading">
+ <span class="panel-header-item">
+ </span>
+ </div>
+ <table class="table">
+ <tr>
+ <th>
+ Health (connection)
+
+ </th><th>
+ Health (api)
+
+ </th><th>
+ Health (dhcp)
+
+ </th><th>
+ vPing (ssh)
+
+ </th><th>
+ vPing (userdata)
+
+ </th><th>
+ Tempest (smoke)
+
+ </th><th>
+ Rally (smoke)
+
+ </th><th>
+ Refstack
+
+ </th><th>
+ SNAPS
+
+ </th><th>
+ Doctor
+
+ </th><th>
+ Domino
+
+ </th>
+ </tr>
+ <tr class="tr-weather-weather">
+ <td><img src="../../img/weather-clear.png"></td><td><img src="../../img/weather-clear.png"></td><td><img src="../../img/weather-storm.png"></td><td><img src="../../img/weather-storm.png"></td><td><img src="../../img/weather-storm.png"></td><td><img src="../../img/weather-storm.png"></td><td><img src="../../img/weather-storm.png"></td><td><img src="../../img/weather-storm.png"></td><td><img src="../../img/weather-storm.png"></td><td><img src="../../img/weather-storm.png"></td><td><img src="../../img/weather-storm.png"></td>
+ </tr>
+ </table>
+ </div>
+ </div><div class="scenario-part">
+ <div class="page-header">
+ <h3><span class="glyphicon glyphicon-chevron-right"> <b>os-odl_l2-fdio-ha</b></h3>
+ </div>
+ <div class="panel panel-default">
+ <div class="panel-heading">
+ <span class="panel-header-item">
+ </span>
+ </div>
+ <table class="table">
+ <tr>
+ <th>
+ Health (connection)
+
+ </th><th>
+ Health (api)
+
+ </th><th>
+ Health (dhcp)
+
+ </th><th>
+ vPing (ssh)
+
+ </th><th>
+ vPing (userdata)
+
+ </th><th>
+ Tempest (smoke)
+
+ </th><th>
+ Rally (smoke)
+
+ </th><th>
+ Refstack
+
+ </th><th>
+ ODL
+
+ </th><th>
+ FDS
+
+ </th><th>
+ SNAPS
+
+ </th><th>
+ Domino
+
+ </th>
+ </tr>
+ <tr class="tr-weather-weather">
+ <td><img src="../../img/weather-clear.png"></td><td><img src="../../img/weather-clear.png"></td><td><img src="../../img/weather-clear.png"></td><td><img src="../../img/weather-clear.png"></td><td><img src="../../img/weather-clear.png"></td><td><img src="../../img/weather-few-clouds.png"></td><td><img src="../../img/weather-clear.png"></td><td><img src="../../img/weather-overcast.png"></td><td><img src="../../img/weather-clear.png"></td><td><img src="../../img/weather-storm.png"></td><td><img src="../../img/weather-clear.png"></td><td><img src="../../img/weather-few-clouds.png"></td>
+ </tr>
+ </table>
+ </div>
+ </div><div class="scenario-part">
+ <div class="page-header">
+ <h3><span class="glyphicon glyphicon-chevron-right"> <b>os-nosdn-nofeature-ha</b></h3>
+ </div>
+ <div class="panel panel-default">
+ <div class="panel-heading">
+ <span class="panel-header-item">
+ </span>
+ </div>
+ <table class="table">
+ <tr>
+ <th>
+ Health (connection)
+
+ </th><th>
+ Health (api)
+
+ </th><th>
+ Health (dhcp)
+
+ </th><th>
+ vPing (ssh)
+
+ </th><th>
+ vPing (userdata)
+
+ </th><th>
+ Tempest (smoke)
+
+ </th><th>
+ Rally (smoke)
+
+ </th><th>
+ Refstack
+
+ </th><th>
+ SNAPS
+
+ </th><th>
+ Doctor
+
+ </th><th>
+ Domino
+
+ </th>
+ </tr>
+ <tr class="tr-weather-weather">
+ <td><img src="../../img/weather-clear.png"></td><td><img src="../../img/weather-clear.png"></td><td><img src="../../img/weather-clear.png"></td><td><img src="../../img/weather-clear.png"></td><td><img src="../../img/weather-clear.png"></td><td><img src="../../img/weather-clear.png"></td><td><img src="../../img/weather-clear.png"></td><td><img src="../../img/weather-clear.png"></td><td><img src="../../img/weather-clear.png"></td><td><img src="../../img/weather-clear.png"></td><td><img src="../../img/weather-storm.png"></td>
+ </tr>
+ </table>
+ </div>
+ </div><div class="scenario-part">
+ <div class="page-header">
+ <h3><span class="glyphicon glyphicon-chevron-right"> <b>os-odl_l3-fdio-ha</b></h3>
+ </div>
+ <div class="panel panel-default">
+ <div class="panel-heading">
+ <span class="panel-header-item">
+ </span>
+ </div>
+ <table class="table">
+ <tr>
+ <th>
+ Health (connection)
+
+ </th><th>
+ Health (api)
+
+ </th><th>
+ Health (dhcp)
+
+ </th><th>
+ vPing (userdata)
+
+ </th><th>
+ Tempest (smoke)
+
+ </th><th>
+ Rally (smoke)
+
+ </th><th>
+ Refstack
+
+ </th><th>
+ ODL
+
+ </th><th>
+ SNAPS
+
+ </th><th>
+ Domino
+
+ </th>
+ </tr>
+ <tr class="tr-weather-weather">
+ <td><img src="../../img/weather-clear.png"></td><td><img src="../../img/weather-clear.png"></td><td><img src="../../img/weather-few-clouds.png"></td><td><img src="../../img/weather-clear.png"></td><td><img src="../../img/weather-storm.png"></td><td><img src="../../img/weather-clear.png"></td><td><img src="../../img/weather-storm.png"></td><td><img src="../../img/weather-clear.png"></td><td><img src="../../img/weather-clear.png"></td><td><img src="../../img/weather-clear.png"></td>
+ </tr>
+ </table>
+ </div>
+ </div>
+ see <a href="https://wiki.opnfv.org/pages/viewpage.action?pageId=6828617">Functest scoring wiki page</a> for details on scenario scoring
+ <div> <br>
+ <a href="./status-apex.pdf" class="myButtonPdf">Export to PDF</a> <a href="./scenario_history_apex.txt" class="myButtonCSV">Export to CSV</a>
+ </div>
+ </div>
+ <div class="col-md-1"></div>
+</div>
diff --git a/docs/results/danube/2.0/compass.html b/docs/results/danube/2.0/compass.html
new file mode 100644
index 000000000..cde66359f
--- /dev/null
+++ b/docs/results/danube/2.0/compass.html
@@ -0,0 +1,493 @@
+ <html>
+ <head>
+ <meta charset="utf-8">
+ <!-- Bootstrap core CSS -->
+ <link href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.4/css/bootstrap.min.css" rel="stylesheet">
+ <link href="../../js/default.css" rel="stylesheet">
+ <script type="text/javascript" src="http://ajax.googleapis.com/ajax/libs/jquery/1/jquery.min.js"></script>
+ <script type="text/javascript" src="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.4/js/bootstrap.min.js"></script>
+ <script type="text/javascript" src="http://d3js.org/d3.v2.min.js"></script>
+ <script type="text/javascript" src="../../js/gauge.js"></script>
+ <script type="text/javascript" src="../../js/trend.js"></script>
+ <script>
+ function onDocumentReady() {
+ // Gauge management
+ var gaugeScenario1 = gauge('#gaugeScenario1');var gaugeScenario2 = gauge('#gaugeScenario2');var gaugeScenario3 = gauge('#gaugeScenario3');var gaugeScenario4 = gauge('#gaugeScenario4');var gaugeScenario5 = gauge('#gaugeScenario5');var gaugeScenario6 = gauge('#gaugeScenario6');
+
+ // assign success rate to the gauge
+ function updateReadings() {
+ gaugeScenario1.update(83.3333333333);gaugeScenario2.update(10.0);gaugeScenario3.update(84.8484848485);gaugeScenario4.update(84.8484848485);gaugeScenario5.update(96.6666666667);gaugeScenario6.update(96.6666666667);
+ }
+ updateReadings();
+ }
+
+ // trend line management
+ d3.csv("./scenario_history.txt", function(data) {
+ // ***************************************
+ // Create the trend line
+ // for scenario os-odl_l3-nofeature-ha
+ // Filter results
+ var trend1 = data.filter(function(row) {
+ return row["scenario"]=="os-odl_l3-nofeature-ha" && row["installer"]=="compass";
+ })
+ // Parse the date
+ trend1.forEach(function(d) {
+ d.date = parseDate(d.date);
+ d.score = +d.score
+ });
+ // Draw the trend line
+ var mytrend = trend("#trend_svg1",trend1)
+ // ****************************************// for scenario os-ocl-nofeature-ha
+ // Filter results
+ var trend2 = data.filter(function(row) {
+ return row["scenario"]=="os-ocl-nofeature-ha" && row["installer"]=="compass";
+ })
+ // Parse the date
+ trend2.forEach(function(d) {
+ d.date = parseDate(d.date);
+ d.score = +d.score
+ });
+ // Draw the trend line
+ var mytrend = trend("#trend_svg2",trend2)
+ // ****************************************// for scenario os-onos-nofeature-ha
+ // Filter results
+ var trend3 = data.filter(function(row) {
+ return row["scenario"]=="os-onos-nofeature-ha" && row["installer"]=="compass";
+ })
+ // Parse the date
+ trend3.forEach(function(d) {
+ d.date = parseDate(d.date);
+ d.score = +d.score
+ });
+ // Draw the trend line
+ var mytrend = trend("#trend_svg3",trend3)
+ // ****************************************// for scenario os-odl_l2-nofeature-ha
+ // Filter results
+ var trend4 = data.filter(function(row) {
+ return row["scenario"]=="os-odl_l2-nofeature-ha" && row["installer"]=="compass";
+ })
+ // Parse the date
+ trend4.forEach(function(d) {
+ d.date = parseDate(d.date);
+ d.score = +d.score
+ });
+ // Draw the trend line
+ var mytrend = trend("#trend_svg4",trend4)
+ // ****************************************// for scenario os-nosdn-openo-ha
+ // Filter results
+ var trend5 = data.filter(function(row) {
+ return row["scenario"]=="os-nosdn-openo-ha" && row["installer"]=="compass";
+ })
+ // Parse the date
+ trend5.forEach(function(d) {
+ d.date = parseDate(d.date);
+ d.score = +d.score
+ });
+ // Draw the trend line
+ var mytrend = trend("#trend_svg5",trend5)
+ // ****************************************// for scenario os-nosdn-nofeature-ha
+ // Filter results
+ var trend6 = data.filter(function(row) {
+ return row["scenario"]=="os-nosdn-nofeature-ha" && row["installer"]=="compass";
+ })
+ // Parse the date
+ trend6.forEach(function(d) {
+ d.date = parseDate(d.date);
+ d.score = +d.score
+ });
+ // Draw the trend line
+ var mytrend = trend("#trend_svg6",trend6)
+ // ****************************************
+ });
+ if ( !window.isLoaded ) {
+ window.addEventListener("load", function() {
+ onDocumentReady();
+ }, false);
+ } else {
+ onDocumentReady();
+ }
+</script>
+<script type="text/javascript">
+$(document).ready(function (){
+ $(".btn-more").click(function() {
+ $(this).hide();
+ $(this).parent().find(".panel-default").show();
+ });
+})
+</script>
+
+ </head>
+ <body>
+ <div class="container">
+ <div class="masthead">
+ <h3 class="text-muted">Functest status page (danube, 2017-05-05 01:45)</h3>
+ <nav>
+ <ul class="nav nav-justified">
+ <li class="active"><a href="http://testresults.opnfv.org/reporting/index.html">Home</a></li>
+ <li><a href="apex.html">Apex</a></li>
+ <li><a href="compass.html">Compass</a></li>
+ <li><a href="fuel.html">Fuel</a></li>
+ <li><a href="joid.html">Joid</a></li>
+ </ul>
+ </nav>
+ </div>
+<div class="row">
+ <div class="col-md-1"></div>
+ <div class="col-md-10">
+ <div class="page-header">
+ <h2>compass</h2>
+ </div>
+
+ <div class="scenario-overview">
+ <div class="panel-heading"><h4><b>List of last scenarios (danube) run over the last 10 days </b></h4></div>
+ <table class="table">
+ <tr>
+ <th width="40%">Scenario</th>
+ <th width="20%">Status</th>
+ <th width="20%">Trend</th>
+ <th width="10%">Score</th>
+ <th width="10%">Iteration</th>
+ </tr>
+ <tr class="tr-ok">
+ <td><a href=https://build.opnfv.org/ci/view/functest/job/functest-compass-virtual-daily-danube/217/console>os-odl_l3-nofeature-ha</a></td>
+ <td><div id="gaugeScenario1"></div></td>
+ <td><div id="trend_svg1"></div></td>
+ <td>25/30</td>
+ <td>18</td>
+ </tr><tr class="tr-ok">
+ <td><a href=https://build.opnfv.org/ci/view/functest/job/functest-compass-baremetal-daily-danube/222/console>os-ocl-nofeature-ha</a></td>
+ <td><div id="gaugeScenario2"></div></td>
+ <td><div id="trend_svg2"></div></td>
+ <td>3/30</td>
+ <td>7</td>
+ </tr><tr class="tr-ok">
+ <td><a href=https://build.opnfv.org/ci/view/functest/job/functest-compass-virtual-daily-danube/213/console>os-onos-nofeature-ha</a></td>
+ <td><div id="gaugeScenario3"></div></td>
+ <td><div id="trend_svg3"></div></td>
+ <td>28/33</td>
+ <td>16</td>
+ </tr><tr class="tr-ok">
+ <td><a href=https://build.opnfv.org/ci/view/functest/job/functest-compass-virtual-daily-danube/218/console>os-odl_l2-nofeature-ha</a></td>
+ <td><div id="gaugeScenario4"></div></td>
+ <td><div id="trend_svg4"></div></td>
+ <td>28/33</td>
+ <td>18</td>
+ </tr><tr class="tr-ok">
+ <td><a href=https://build.opnfv.org/ci/view/functest/job/functest-compass-virtual-daily-danube/212/console>os-nosdn-openo-ha</a></td>
+ <td><div id="gaugeScenario5"></div></td>
+ <td><div id="trend_svg5"></div></td>
+ <td>29/30</td>
+ <td>7</td>
+ </tr><tr class="tr-ok">
+ <td><a href=https://build.opnfv.org/ci/view/functest/job/functest-compass-baremetal-daily-danube/224/console>os-nosdn-nofeature-ha</a></td>
+ <td><div id="gaugeScenario6"></div></td>
+ <td><div id="trend_svg6"></div></td>
+ <td>29/30</td>
+ <td>18</td>
+ </tr>
+ </table>
+ </div>
+
+
+ <div class="scenario-part">
+ <div class="page-header">
+ <h3><span class="glyphicon glyphicon-chevron-right"> <b>os-odl_l3-nofeature-ha</b></h3>
+ </div>
+ <div class="panel panel-default">
+ <div class="panel-heading">
+ <span class="panel-header-item">
+ </span>
+ </div>
+ <table class="table">
+ <tr>
+ <th>
+ Health (connection)
+
+ </th><th>
+ Health (api)
+
+ </th><th>
+ Health (dhcp)
+
+ </th><th>
+ vPing (userdata)
+
+ </th><th>
+ Tempest (smoke)
+
+ </th><th>
+ Rally (smoke)
+
+ </th><th>
+ Refstack
+
+ </th><th>
+ ODL
+
+ </th><th>
+ SNAPS
+
+ </th><th>
+ Domino
+
+ </th>
+ </tr>
+ <tr class="tr-weather-weather">
+ <td><img src="../../img/weather-clear.png"></td><td><img src="../../img/weather-clear.png"></td><td><img src="../../img/weather-few-clouds.png"></td><td><img src="../../img/weather-clear.png"></td><td><img src="../../img/weather-few-clouds.png"></td><td><img src="../../img/weather-few-clouds.png"></td><td><img src="../../img/weather-few-clouds.png"></td><td><img src="../../img/weather-clear.png"></td><td><img src="../../img/weather-few-clouds.png"></td><td><img src="../../img/weather-clear.png"></td>
+ </tr>
+ </table>
+ </div>
+ </div><div class="scenario-part">
+ <div class="page-header">
+ <h3><span class="glyphicon glyphicon-chevron-right"> <b>os-ocl-nofeature-ha</b></h3>
+ </div>
+ <div class="panel panel-default">
+ <div class="panel-heading">
+ <span class="panel-header-item">
+ </span>
+ </div>
+ <table class="table">
+ <tr>
+ <th>
+ Health (connection)
+
+ </th><th>
+ Health (api)
+
+ </th><th>
+ Health (dhcp)
+
+ </th><th>
+ vPing (ssh)
+
+ </th><th>
+ vPing (userdata)
+
+ </th><th>
+ Tempest (smoke)
+
+ </th><th>
+ Rally (smoke)
+
+ </th><th>
+ Refstack
+
+ </th><th>
+ SNAPS
+
+ </th><th>
+ Domino
+
+ </th>
+ </tr>
+ <tr class="tr-weather-weather">
+ <td><img src="../../img/weather-clear.png"></td><td><img src="../../img/weather-storm.png"></td><td><img src="../../img/weather-storm.png"></td><td><img src="../../img/weather-storm.png"></td><td><img src="../../img/weather-storm.png"></td><td><img src="../../img/weather-storm.png"></td><td><img src="../../img/weather-storm.png"></td><td><img src="../../img/weather-storm.png"></td><td><img src="../../img/weather-storm.png"></td><td><img src="../../img/weather-storm.png"></td>
+ </tr>
+ </table>
+ </div>
+ </div><div class="scenario-part">
+ <div class="page-header">
+ <h3><span class="glyphicon glyphicon-chevron-right"> <b>os-onos-nofeature-ha</b></h3>
+ </div>
+ <div class="panel panel-default">
+ <div class="panel-heading">
+ <span class="panel-header-item">
+ </span>
+ </div>
+ <table class="table">
+ <tr>
+ <th>
+ Health (connection)
+
+ </th><th>
+ Health (api)
+
+ </th><th>
+ Health (dhcp)
+
+ </th><th>
+ vPing (ssh)
+
+ </th><th>
+ vPing (userdata)
+
+ </th><th>
+ Tempest (smoke)
+
+ </th><th>
+ Rally (smoke)
+
+ </th><th>
+ Refstack
+
+ </th><th>
+ ONOS
+
+ </th><th>
+ SNAPS
+
+ </th><th>
+ Domino
+
+ </th>
+ </tr>
+ <tr class="tr-weather-weather">
+ <td><img src="../../img/weather-clear.png"></td><td><img src="../../img/weather-clear.png"></td><td><img src="../../img/weather-clear.png"></td><td><img src="../../img/weather-clear.png"></td><td><img src="../../img/weather-clear.png"></td><td><img src="../../img/weather-clear.png"></td><td><img src="../../img/weather-few-clouds.png"></td><td><img src="../../img/weather-storm.png"></td><td><img src="../../img/weather-clear.png"></td><td><img src="../../img/weather-few-clouds.png"></td><td><img src="../../img/weather-clear.png"></td>
+ </tr>
+ </table>
+ </div>
+ </div><div class="scenario-part">
+ <div class="page-header">
+ <h3><span class="glyphicon glyphicon-chevron-right"> <b>os-odl_l2-nofeature-ha</b></h3>
+ </div>
+ <div class="panel panel-default">
+ <div class="panel-heading">
+ <span class="panel-header-item">
+ </span>
+ </div>
+ <table class="table">
+ <tr>
+ <th>
+ Health (connection)
+
+ </th><th>
+ Health (api)
+
+ </th><th>
+ Health (dhcp)
+
+ </th><th>
+ vPing (ssh)
+
+ </th><th>
+ vPing (userdata)
+
+ </th><th>
+ Tempest (smoke)
+
+ </th><th>
+ Rally (smoke)
+
+ </th><th>
+ Refstack
+
+ </th><th>
+ ODL
+
+ </th><th>
+ SNAPS
+
+ </th><th>
+ Domino
+
+ </th>
+ </tr>
+ <tr class="tr-weather-weather">
+ <td><img src="../../img/weather-clear.png"></td><td><img src="../../img/weather-clear.png"></td><td><img src="../../img/weather-clear.png"></td><td><img src="../../img/weather-clear.png"></td><td><img src="../../img/weather-clear.png"></td><td><img src="../../img/weather-overcast.png"></td><td><img src="../../img/weather-few-clouds.png"></td><td><img src="../../img/weather-few-clouds.png"></td><td><img src="../../img/weather-clear.png"></td><td><img src="../../img/weather-few-clouds.png"></td><td><img src="../../img/weather-clear.png"></td>
+ </tr>
+ </table>
+ </div>
+ </div><div class="scenario-part">
+ <div class="page-header">
+ <h3><span class="glyphicon glyphicon-chevron-right"> <b>os-nosdn-openo-ha</b></h3>
+ </div>
+ <div class="panel panel-default">
+ <div class="panel-heading">
+ <span class="panel-header-item">
+ </span>
+ </div>
+ <table class="table">
+ <tr>
+ <th>
+ Health (connection)
+
+ </th><th>
+ Health (api)
+
+ </th><th>
+ Health (dhcp)
+
+ </th><th>
+ vPing (ssh)
+
+ </th><th>
+ vPing (userdata)
+
+ </th><th>
+ Tempest (smoke)
+
+ </th><th>
+ Rally (smoke)
+
+ </th><th>
+ Refstack
+
+ </th><th>
+ SNAPS
+
+ </th><th>
+ Domino
+
+ </th>
+ </tr>
+ <tr class="tr-weather-weather">
+ <td><img src="../../img/weather-clear.png"></td><td><img src="../../img/weather-clear.png"></td><td><img src="../../img/weather-clear.png"></td><td><img src="../../img/weather-clear.png"></td><td><img src="../../img/weather-clear.png"></td><td><img src="../../img/weather-clear.png"></td><td><img src="../../img/weather-clear.png"></td><td><img src="../../img/weather-clear.png"></td><td><img src="../../img/weather-few-clouds.png"></td><td><img src="../../img/weather-clear.png"></td>
+ </tr>
+ </table>
+ </div>
+ </div><div class="scenario-part">
+ <div class="page-header">
+ <h3><span class="glyphicon glyphicon-chevron-right"> <b>os-nosdn-nofeature-ha</b></h3>
+ </div>
+ <div class="panel panel-default">
+ <div class="panel-heading">
+ <span class="panel-header-item">
+ </span>
+ </div>
+ <table class="table">
+ <tr>
+ <th>
+ Health (connection)
+
+ </th><th>
+ Health (api)
+
+ </th><th>
+ Health (dhcp)
+
+ </th><th>
+ vPing (ssh)
+
+ </th><th>
+ vPing (userdata)
+
+ </th><th>
+ Tempest (smoke)
+
+ </th><th>
+ Rally (smoke)
+
+ </th><th>
+ Refstack
+
+ </th><th>
+ SNAPS
+
+ </th><th>
+ Domino
+
+ </th>
+ </tr>
+ <tr class="tr-weather-weather">
+ <td><img src="../../img/weather-clear.png"></td><td><img src="../../img/weather-clear.png"></td><td><img src="../../img/weather-few-clouds.png"></td><td><img src="../../img/weather-clear.png"></td><td><img src="../../img/weather-clear.png"></td><td><img src="../../img/weather-clear.png"></td><td><img src="../../img/weather-clear.png"></td><td><img src="../../img/weather-clear.png"></td><td><img src="../../img/weather-clear.png"></td><td><img src="../../img/weather-clear.png"></td>
+ </tr>
+ </table>
+ </div>
+ </div>
+ see <a href="https://wiki.opnfv.org/pages/viewpage.action?pageId=6828617">Functest scoring wiki page</a> for details on scenario scoring
+ <div> <br>
+ <a href="./status-compass.pdf" class="myButtonPdf">Export to PDF</a> <a href="./scenario_history_compass.txt" class="myButtonCSV">Export to CSV</a>
+ </div>
+ </div>
+ <div class="col-md-1"></div>
+</div>
diff --git a/docs/results/danube/2.0/fuel.html b/docs/results/danube/2.0/fuel.html
new file mode 100644
index 000000000..0ee69d3bf
--- /dev/null
+++ b/docs/results/danube/2.0/fuel.html
@@ -0,0 +1,1447 @@
+ <html>
+ <head>
+ <meta charset="utf-8">
+ <!-- Bootstrap core CSS -->
+ <link href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.4/css/bootstrap.min.css" rel="stylesheet">
+ <link href="../../js/default.css" rel="stylesheet">
+ <script type="text/javascript" src="http://ajax.googleapis.com/ajax/libs/jquery/1/jquery.min.js"></script>
+ <script type="text/javascript" src="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.4/js/bootstrap.min.js"></script>
+ <script type="text/javascript" src="http://d3js.org/d3.v2.min.js"></script>
+ <script type="text/javascript" src="../../js/gauge.js"></script>
+ <script type="text/javascript" src="../../js/trend.js"></script>
+ <script>
+ function onDocumentReady() {
+ // Gauge management
+ var gaugeScenario1 = gauge('#gaugeScenario1');var gaugeScenario2 = gauge('#gaugeScenario2');var gaugeScenario3 = gauge('#gaugeScenario3');var gaugeScenario4 = gauge('#gaugeScenario4');var gaugeScenario5 = gauge('#gaugeScenario5');var gaugeScenario6 = gauge('#gaugeScenario6');var gaugeScenario7 = gauge('#gaugeScenario7');var gaugeScenario8 = gauge('#gaugeScenario8');var gaugeScenario9 = gauge('#gaugeScenario9');var gaugeScenario10 = gauge('#gaugeScenario10');var gaugeScenario11 = gauge('#gaugeScenario11');var gaugeScenario12 = gauge('#gaugeScenario12');var gaugeScenario13 = gauge('#gaugeScenario13');var gaugeScenario14 = gauge('#gaugeScenario14');var gaugeScenario15 = gauge('#gaugeScenario15');var gaugeScenario16 = gauge('#gaugeScenario16');var gaugeScenario17 = gauge('#gaugeScenario17');var gaugeScenario18 = gauge('#gaugeScenario18');
+
+ // assign success rate to the gauge
+ function updateReadings() {
+ gaugeScenario1.update(100.0);gaugeScenario2.update(28.5714285714);gaugeScenario3.update(100.0);gaugeScenario4.update(100.0);gaugeScenario5.update(15.3846153846);gaugeScenario6.update(95.2380952381);gaugeScenario7.update(94.8717948718);gaugeScenario8.update(100.0);gaugeScenario9.update(100.0);gaugeScenario10.update(97.4358974359);gaugeScenario11.update(92.8571428571);gaugeScenario12.update(100.0);gaugeScenario13.update(97.4358974359);gaugeScenario14.update(100.0);gaugeScenario15.update(95.2380952381);gaugeScenario16.update(100.0);gaugeScenario17.update(100.0);gaugeScenario18.update(100.0);
+ }
+ updateReadings();
+ }
+
+ // trend line management
+ d3.csv("./scenario_history.txt", function(data) {
+ // ***************************************
+ // Create the trend line
+ // for scenario os-nosdn-kvm_ovs_dpdk-noha
+ // Filter results
+ var trend1 = data.filter(function(row) {
+ return row["scenario"]=="os-nosdn-kvm_ovs_dpdk-noha" && row["installer"]=="fuel";
+ })
+ // Parse the date
+ trend1.forEach(function(d) {
+ d.date = parseDate(d.date);
+ d.score = +d.score
+ });
+ // Draw the trend line
+ var mytrend = trend("#trend_svg1",trend1)
+ // ****************************************// for scenario os-nosdn-kvm_ovs_dpdk_bar-ha
+ // Filter results
+ var trend2 = data.filter(function(row) {
+ return row["scenario"]=="os-nosdn-kvm_ovs_dpdk_bar-ha" && row["installer"]=="fuel";
+ })
+ // Parse the date
+ trend2.forEach(function(d) {
+ d.date = parseDate(d.date);
+ d.score = +d.score
+ });
+ // Draw the trend line
+ var mytrend = trend("#trend_svg2",trend2)
+ // ****************************************// for scenario os-nosdn-ovs-ha
+ // Filter results
+ var trend3 = data.filter(function(row) {
+ return row["scenario"]=="os-nosdn-ovs-ha" && row["installer"]=="fuel";
+ })
+ // Parse the date
+ trend3.forEach(function(d) {
+ d.date = parseDate(d.date);
+ d.score = +d.score
+ });
+ // Draw the trend line
+ var mytrend = trend("#trend_svg3",trend3)
+ // ****************************************// for scenario os-nosdn-ovs-noha
+ // Filter results
+ var trend4 = data.filter(function(row) {
+ return row["scenario"]=="os-nosdn-ovs-noha" && row["installer"]=="fuel";
+ })
+ // Parse the date
+ trend4.forEach(function(d) {
+ d.date = parseDate(d.date);
+ d.score = +d.score
+ });
+ // Draw the trend line
+ var mytrend = trend("#trend_svg4",trend4)
+ // ****************************************// for scenario os-nosdn-kvm_ovs_dpdk-ha
+ // Filter results
+ var trend5 = data.filter(function(row) {
+ return row["scenario"]=="os-nosdn-kvm_ovs_dpdk-ha" && row["installer"]=="fuel";
+ })
+ // Parse the date
+ trend5.forEach(function(d) {
+ d.date = parseDate(d.date);
+ d.score = +d.score
+ });
+ // Draw the trend line
+ var mytrend = trend("#trend_svg5",trend5)
+ // ****************************************// for scenario os-odl_l2-sfc-noha
+ // Filter results
+ var trend6 = data.filter(function(row) {
+ return row["scenario"]=="os-odl_l2-sfc-noha" && row["installer"]=="fuel";
+ })
+ // Parse the date
+ trend6.forEach(function(d) {
+ d.date = parseDate(d.date);
+ d.score = +d.score
+ });
+ // Draw the trend line
+ var mytrend = trend("#trend_svg6",trend6)
+ // ****************************************// for scenario os-odl_l3-nofeature-ha
+ // Filter results
+ var trend7 = data.filter(function(row) {
+ return row["scenario"]=="os-odl_l3-nofeature-ha" && row["installer"]=="fuel";
+ })
+ // Parse the date
+ trend7.forEach(function(d) {
+ d.date = parseDate(d.date);
+ d.score = +d.score
+ });
+ // Draw the trend line
+ var mytrend = trend("#trend_svg7",trend7)
+ // ****************************************// for scenario os-nosdn-kvm-noha
+ // Filter results
+ var trend8 = data.filter(function(row) {
+ return row["scenario"]=="os-nosdn-kvm-noha" && row["installer"]=="fuel";
+ })
+ // Parse the date
+ trend8.forEach(function(d) {
+ d.date = parseDate(d.date);
+ d.score = +d.score
+ });
+ // Draw the trend line
+ var mytrend = trend("#trend_svg8",trend8)
+ // ****************************************// for scenario os-odl_l3-nofeature-noha
+ // Filter results
+ var trend9 = data.filter(function(row) {
+ return row["scenario"]=="os-odl_l3-nofeature-noha" && row["installer"]=="fuel";
+ })
+ // Parse the date
+ trend9.forEach(function(d) {
+ d.date = parseDate(d.date);
+ d.score = +d.score
+ });
+ // Draw the trend line
+ var mytrend = trend("#trend_svg9",trend9)
+ // ****************************************// for scenario os-odl_l2-nofeature-noha
+ // Filter results
+ var trend10 = data.filter(function(row) {
+ return row["scenario"]=="os-odl_l2-nofeature-noha" && row["installer"]=="fuel";
+ })
+ // Parse the date
+ trend10.forEach(function(d) {
+ d.date = parseDate(d.date);
+ d.score = +d.score
+ });
+ // Draw the trend line
+ var mytrend = trend("#trend_svg10",trend10)
+ // ****************************************// for scenario os-odl_l2-bgpvpn-ha
+ // Filter results
+ var trend11 = data.filter(function(row) {
+ return row["scenario"]=="os-odl_l2-bgpvpn-ha" && row["installer"]=="fuel";
+ })
+ // Parse the date
+ trend11.forEach(function(d) {
+ d.date = parseDate(d.date);
+ d.score = +d.score
+ });
+ // Draw the trend line
+ var mytrend = trend("#trend_svg11",trend11)
+ // ****************************************// for scenario os-odl_l2-sfc-ha
+ // Filter results
+ var trend12 = data.filter(function(row) {
+ return row["scenario"]=="os-odl_l2-sfc-ha" && row["installer"]=="fuel";
+ })
+ // Parse the date
+ trend12.forEach(function(d) {
+ d.date = parseDate(d.date);
+ d.score = +d.score
+ });
+ // Draw the trend line
+ var mytrend = trend("#trend_svg12",trend12)
+ // ****************************************// for scenario os-nosdn-kvm_ovs_dpdk_bar-noha
+ // Filter results
+ var trend13 = data.filter(function(row) {
+ return row["scenario"]=="os-nosdn-kvm_ovs_dpdk_bar-noha" && row["installer"]=="fuel";
+ })
+ // Parse the date
+ trend13.forEach(function(d) {
+ d.date = parseDate(d.date);
+ d.score = +d.score
+ });
+ // Draw the trend line
+ var mytrend = trend("#trend_svg13",trend13)
+ // ****************************************// for scenario os-odl_l2-bgpvpn-noha
+ // Filter results
+ var trend14 = data.filter(function(row) {
+ return row["scenario"]=="os-odl_l2-bgpvpn-noha" && row["installer"]=="fuel";
+ })
+ // Parse the date
+ trend14.forEach(function(d) {
+ d.date = parseDate(d.date);
+ d.score = +d.score
+ });
+ // Draw the trend line
+ var mytrend = trend("#trend_svg14",trend14)
+ // ****************************************// for scenario os-odl_l2-nofeature-ha
+ // Filter results
+ var trend15 = data.filter(function(row) {
+ return row["scenario"]=="os-odl_l2-nofeature-ha" && row["installer"]=="fuel";
+ })
+ // Parse the date
+ trend15.forEach(function(d) {
+ d.date = parseDate(d.date);
+ d.score = +d.score
+ });
+ // Draw the trend line
+ var mytrend = trend("#trend_svg15",trend15)
+ // ****************************************// for scenario os-nosdn-nofeature-noha
+ // Filter results
+ var trend16 = data.filter(function(row) {
+ return row["scenario"]=="os-nosdn-nofeature-noha" && row["installer"]=="fuel";
+ })
+ // Parse the date
+ trend16.forEach(function(d) {
+ d.date = parseDate(d.date);
+ d.score = +d.score
+ });
+ // Draw the trend line
+ var mytrend = trend("#trend_svg16",trend16)
+ // ****************************************// for scenario os-nosdn-kvm-ha
+ // Filter results
+ var trend17 = data.filter(function(row) {
+ return row["scenario"]=="os-nosdn-kvm-ha" && row["installer"]=="fuel";
+ })
+ // Parse the date
+ trend17.forEach(function(d) {
+ d.date = parseDate(d.date);
+ d.score = +d.score
+ });
+ // Draw the trend line
+ var mytrend = trend("#trend_svg17",trend17)
+ // ****************************************// for scenario os-nosdn-nofeature-ha
+ // Filter results
+ var trend18 = data.filter(function(row) {
+ return row["scenario"]=="os-nosdn-nofeature-ha" && row["installer"]=="fuel";
+ })
+ // Parse the date
+ trend18.forEach(function(d) {
+ d.date = parseDate(d.date);
+ d.score = +d.score
+ });
+ // Draw the trend line
+ var mytrend = trend("#trend_svg18",trend18)
+ // ****************************************
+ });
+ if ( !window.isLoaded ) {
+ window.addEventListener("load", function() {
+ onDocumentReady();
+ }, false);
+ } else {
+ onDocumentReady();
+ }
+</script>
+<script type="text/javascript">
+$(document).ready(function (){
+ $(".btn-more").click(function() {
+ $(this).hide();
+ $(this).parent().find(".panel-default").show();
+ });
+})
+</script>
+
+ </head>
+ <body>
+ <div class="container">
+ <div class="masthead">
+ <h3 class="text-muted">Functest status page (danube, 2017-05-05 01:45)</h3>
+ <nav>
+ <ul class="nav nav-justified">
+ <li class="active"><a href="http://testresults.opnfv.org/reporting/index.html">Home</a></li>
+ <li><a href="apex.html">Apex</a></li>
+ <li><a href="compass.html">Compass</a></li>
+ <li><a href="fuel.html">Fuel</a></li>
+ <li><a href="joid.html">Joid</a></li>
+ </ul>
+ </nav>
+ </div>
+<div class="row">
+ <div class="col-md-1"></div>
+ <div class="col-md-10">
+ <div class="page-header">
+ <h2>fuel</h2>
+ </div>
+
+ <div class="scenario-overview">
+ <div class="panel-heading"><h4><b>List of last scenarios (danube) run over the last 10 days </b></h4></div>
+ <table class="table">
+ <tr>
+ <th width="40%">Scenario</th>
+ <th width="20%">Status</th>
+ <th width="20%">Trend</th>
+ <th width="10%">Score</th>
+ <th width="10%">Iteration</th>
+ </tr>
+ <tr class="tr-ok">
+ <td><a href=https://build.opnfv.org/ci/view/functest/job/functest-fuel-virtual-daily-danube/368/console>os-nosdn-kvm_ovs_dpdk-noha</a></td>
+ <td><div id="gaugeScenario1"></div></td>
+ <td><div id="trend_svg1"></div></td>
+ <td>36/36</td>
+ <td>10</td>
+ </tr><tr class="tr-ok">
+ <td><a href=https://build.opnfv.org/ci/view/functest/job/functest-fuel-baremetal-daily-danube/348/console>os-nosdn-kvm_ovs_dpdk_bar-ha</a></td>
+ <td><div id="gaugeScenario2"></div></td>
+ <td><div id="trend_svg2"></div></td>
+ <td>12/42</td>
+ <td>6</td>
+ </tr><tr class="tr-ok">
+ <td><a href=https://build.opnfv.org/ci/view/functest/job/functest-fuel-baremetal-daily-danube/345/console>os-nosdn-ovs-ha</a></td>
+ <td><div id="gaugeScenario3"></div></td>
+ <td><div id="trend_svg3"></div></td>
+ <td>39/39</td>
+ <td>7</td>
+ </tr><tr class="tr-ok">
+ <td><a href=https://build.opnfv.org/ci/view/functest/job/functest-fuel-virtual-daily-danube/365/console>os-nosdn-ovs-noha</a></td>
+ <td><div id="gaugeScenario4"></div></td>
+ <td><div id="trend_svg4"></div></td>
+ <td>36/36</td>
+ <td>10</td>
+ </tr><tr class="tr-ok">
+ <td><a href=https://build.opnfv.org/ci/view/functest/job/functest-fuel-baremetal-daily-danube/341/console>os-nosdn-kvm_ovs_dpdk-ha</a></td>
+ <td><div id="gaugeScenario5"></div></td>
+ <td><div id="trend_svg5"></div></td>
+ <td>6/39</td>
+ <td>4</td>
+ </tr><tr class="tr-ok">
+ <td><a href=https://build.opnfv.org/ci/view/functest/job/functest-fuel-virtual-daily-danube/362/console>os-odl_l2-sfc-noha</a></td>
+ <td><div id="gaugeScenario6"></div></td>
+ <td><div id="trend_svg6"></div></td>
+ <td>40/42</td>
+ <td>10</td>
+ </tr><tr class="tr-ok">
+ <td><a href=https://build.opnfv.org/ci/view/functest/job/functest-fuel-baremetal-daily-danube/347/console>os-odl_l3-nofeature-ha</a></td>
+ <td><div id="gaugeScenario7"></div></td>
+ <td><div id="trend_svg7"></div></td>
+ <td>37/39</td>
+ <td>8</td>
+ </tr><tr class="tr-ok">
+ <td><a href=https://build.opnfv.org/ci/view/functest/job/functest-fuel-virtual-daily-danube/364/console>os-nosdn-kvm-noha</a></td>
+ <td><div id="gaugeScenario8"></div></td>
+ <td><div id="trend_svg8"></div></td>
+ <td>36/36</td>
+ <td>9</td>
+ </tr><tr class="tr-ok">
+ <td><a href=https://build.opnfv.org/ci/view/functest/job/functest-fuel-virtual-daily-danube/369/console>os-odl_l3-nofeature-noha</a></td>
+ <td><div id="gaugeScenario9"></div></td>
+ <td><div id="trend_svg9"></div></td>
+ <td>36/36</td>
+ <td>9</td>
+ </tr><tr class="tr-ok">
+ <td><a href=https://build.opnfv.org/ci/view/functest/job/functest-fuel-virtual-daily-danube/367/console>os-odl_l2-nofeature-noha</a></td>
+ <td><div id="gaugeScenario10"></div></td>
+ <td><div id="trend_svg10"></div></td>
+ <td>38/39</td>
+ <td>11</td>
+ </tr><tr class="tr-ok">
+ <td><a href=https://build.opnfv.org/ci/view/functest/job/functest-fuel-baremetal-daily-danube/342/console>os-odl_l2-bgpvpn-ha</a></td>
+ <td><div id="gaugeScenario11"></div></td>
+ <td><div id="trend_svg11"></div></td>
+ <td>39/42</td>
+ <td>6</td>
+ </tr><tr class="tr-ok">
+ <td><a href=https://build.opnfv.org/ci/view/functest/job/functest-fuel-baremetal-daily-danube/340/console>os-odl_l2-sfc-ha</a></td>
+ <td><div id="gaugeScenario12"></div></td>
+ <td><div id="trend_svg12"></div></td>
+ <td>45/45</td>
+ <td>6</td>
+ </tr><tr class="tr-ok">
+ <td><a href=https://build.opnfv.org/ci/view/functest/job/functest-fuel-virtual-daily-danube/370/console>os-nosdn-kvm_ovs_dpdk_bar-noha</a></td>
+ <td><div id="gaugeScenario13"></div></td>
+ <td><div id="trend_svg13"></div></td>
+ <td>38/39</td>
+ <td>11</td>
+ </tr><tr class="tr-ok">
+ <td><a href=https://build.opnfv.org/ci/view/functest/job/functest-fuel-virtual-daily-danube/363/console>os-odl_l2-bgpvpn-noha</a></td>
+ <td><div id="gaugeScenario14"></div></td>
+ <td><div id="trend_svg14"></div></td>
+ <td>42/42</td>
+ <td>10</td>
+ </tr><tr class="tr-ok">
+ <td><a href=https://build.opnfv.org/ci/view/functest/job/functest-fuel-baremetal-daily-danube/346/console>os-odl_l2-nofeature-ha</a></td>
+ <td><div id="gaugeScenario15"></div></td>
+ <td><div id="trend_svg15"></div></td>
+ <td>40/42</td>
+ <td>9</td>
+ </tr><tr class="tr-ok">
+ <td><a href=https://build.opnfv.org/ci/view/functest/job/functest-fuel-virtual-daily-danube/366/console>os-nosdn-nofeature-noha</a></td>
+ <td><div id="gaugeScenario16"></div></td>
+ <td><div id="trend_svg16"></div></td>
+ <td>36/36</td>
+ <td>11</td>
+ </tr><tr class="tr-ok">
+ <td><a href=https://build.opnfv.org/ci/view/functest/job/functest-fuel-zte-pod3-daily-danube/55/console>os-nosdn-kvm-ha</a></td>
+ <td><div id="gaugeScenario17"></div></td>
+ <td><div id="trend_svg17"></div></td>
+ <td>39/39</td>
+ <td>16</td>
+ </tr><tr class="tr-ok">
+ <td><a href=https://build.opnfv.org/ci/view/functest/job/functest-fuel-baremetal-daily-danube/344/console>os-nosdn-nofeature-ha</a></td>
+ <td><div id="gaugeScenario18"></div></td>
+ <td><div id="trend_svg18"></div></td>
+ <td>39/39</td>
+ <td>15</td>
+ </tr>
+ </table>
+ </div>
+
+
+ <div class="scenario-part">
+ <div class="page-header">
+ <h3><span class="glyphicon glyphicon-chevron-right"> <b>os-nosdn-kvm_ovs_dpdk-noha</b></h3>
+ </div>
+ <div class="panel panel-default">
+ <div class="panel-heading">
+ <span class="panel-header-item">
+ </span>
+ </div>
+ <table class="table">
+ <tr>
+ <th>
+ Health (connection)
+
+ </th><th>
+ Health (api)
+
+ </th><th>
+ Health (dhcp)
+
+ </th><th>
+ vPing (ssh)
+
+ </th><th>
+ vPing (userdata)
+
+ </th><th>
+ Tempest (smoke)
+
+ </th><th>
+ Rally (smoke)
+
+ </th><th>
+ Refstack
+
+ </th><th>
+ SNAPS
+
+ </th><th>
+ Promise
+
+ </th><th>
+ Doctor
+
+ </th><th>
+ Domino
+
+ </th>
+ </tr>
+ <tr class="tr-weather-weather">
+ <td><img src="../../img/weather-clear.png"></td><td><img src="../../img/weather-clear.png"></td><td><img src="../../img/weather-clear.png"></td><td><img src="../../img/weather-clear.png"></td><td><img src="../../img/weather-clear.png"></td><td><img src="../../img/weather-clear.png"></td><td><img src="../../img/weather-clear.png"></td><td><img src="../../img/weather-clear.png"></td><td><img src="../../img/weather-clear.png"></td><td><img src="../../img/weather-clear.png"></td><td><img src="../../img/weather-clear.png"></td><td><img src="../../img/weather-clear.png"></td>
+ </tr>
+ </table>
+ </div>
+ </div><div class="scenario-part">
+ <div class="page-header">
+ <h3><span class="glyphicon glyphicon-chevron-right"> <b>os-nosdn-kvm_ovs_dpdk_bar-ha</b></h3>
+ </div>
+ <div class="panel panel-default">
+ <div class="panel-heading">
+ <span class="panel-header-item">
+ </span>
+ </div>
+ <table class="table">
+ <tr>
+ <th>
+ Health (connection)
+
+ </th><th>
+ Health (api)
+
+ </th><th>
+ Health (dhcp)
+
+ </th><th>
+ vPing (ssh)
+
+ </th><th>
+ vPing (userdata)
+
+ </th><th>
+ Tempest (smoke)
+
+ </th><th>
+ Rally (smoke)
+
+ </th><th>
+ Refstack
+
+ </th><th>
+ SNAPS
+
+ </th><th>
+ Promise
+
+ </th><th>
+ Doctor
+
+ </th><th>
+ Parser
+
+ </th><th>
+ Domino
+
+ </th><th>
+ Barometer
+
+ </th>
+ </tr>
+ <tr class="tr-weather-weather">
+ <td><img src="../../img/weather-clear.png"></td><td><img src="../../img/weather-clear.png"></td><td><img src="../../img/weather-overcast.png"></td><td><img src="../../img/weather-overcast.png"></td><td><img src="../../img/weather-overcast.png"></td><td><img src="../../img/weather-overcast.png"></td><td><img src="../../img/weather-overcast.png"></td><td><img src="../../img/weather-overcast.png"></td><td><img src="../../img/weather-storm.png"></td><td><img src="../../img/weather-storm.png"></td><td><img src="../../img/weather-storm.png"></td><td><img src="../../img/weather-storm.png"></td><td><img src="../../img/weather-storm.png"></td><td><img src="../../img/weather-storm.png"></td>
+ </tr>
+ </table>
+ </div>
+ </div><div class="scenario-part">
+ <div class="page-header">
+ <h3><span class="glyphicon glyphicon-chevron-right"> <b>os-nosdn-ovs-ha</b></h3>
+ </div>
+ <div class="panel panel-default">
+ <div class="panel-heading">
+ <span class="panel-header-item">
+ </span>
+ </div>
+ <table class="table">
+ <tr>
+ <th>
+ Health (connection)
+
+ </th><th>
+ Health (api)
+
+ </th><th>
+ Health (dhcp)
+
+ </th><th>
+ vPing (ssh)
+
+ </th><th>
+ vPing (userdata)
+
+ </th><th>
+ Tempest (smoke)
+
+ </th><th>
+ Rally (smoke)
+
+ </th><th>
+ Refstack
+
+ </th><th>
+ SNAPS
+
+ </th><th>
+ Promise
+
+ </th><th>
+ Doctor
+
+ </th><th>
+ Parser
+
+ </th><th>
+ Domino
+
+ </th>
+ </tr>
+ <tr class="tr-weather-weather">
+ <td><img src="../../img/weather-clear.png"></td><td><img src="../../img/weather-clear.png"></td><td><img src="../../img/weather-clear.png"></td><td><img src="../../img/weather-clear.png"></td><td><img src="../../img/weather-clear.png"></td><td><img src="../../img/weather-clear.png"></td><td><img src="../../img/weather-clear.png"></td><td><img src="../../img/weather-clear.png"></td><td><img src="../../img/weather-clear.png"></td><td><img src="../../img/weather-clear.png"></td><td><img src="../../img/weather-clear.png"></td><td><img src="../../img/weather-clear.png"></td><td><img src="../../img/weather-clear.png"></td>
+ </tr>
+ </table>
+ </div>
+ </div><div class="scenario-part">
+ <div class="page-header">
+ <h3><span class="glyphicon glyphicon-chevron-right"> <b>os-nosdn-ovs-noha</b></h3>
+ </div>
+ <div class="panel panel-default">
+ <div class="panel-heading">
+ <span class="panel-header-item">
+ </span>
+ </div>
+ <table class="table">
+ <tr>
+ <th>
+ Health (connection)
+
+ </th><th>
+ Health (api)
+
+ </th><th>
+ Health (dhcp)
+
+ </th><th>
+ vPing (ssh)
+
+ </th><th>
+ vPing (userdata)
+
+ </th><th>
+ Tempest (smoke)
+
+ </th><th>
+ Rally (smoke)
+
+ </th><th>
+ Refstack
+
+ </th><th>
+ SNAPS
+
+ </th><th>
+ Promise
+
+ </th><th>
+ Doctor
+
+ </th><th>
+ Domino
+
+ </th>
+ </tr>
+ <tr class="tr-weather-weather">
+ <td><img src="../../img/weather-clear.png"></td><td><img src="../../img/weather-clear.png"></td><td><img src="../../img/weather-clear.png"></td><td><img src="../../img/weather-clear.png"></td><td><img src="../../img/weather-clear.png"></td><td><img src="../../img/weather-clear.png"></td><td><img src="../../img/weather-clear.png"></td><td><img src="../../img/weather-clear.png"></td><td><img src="../../img/weather-clear.png"></td><td><img src="../../img/weather-clear.png"></td><td><img src="../../img/weather-clear.png"></td><td><img src="../../img/weather-clear.png"></td>
+ </tr>
+ </table>
+ </div>
+ </div><div class="scenario-part">
+ <div class="page-header">
+ <h3><span class="glyphicon glyphicon-chevron-right"> <b>os-nosdn-kvm_ovs_dpdk-ha</b></h3>
+ </div>
+ <div class="panel panel-default">
+ <div class="panel-heading">
+ <span class="panel-header-item">
+ </span>
+ </div>
+ <table class="table">
+ <tr>
+ <th>
+ Health (connection)
+
+ </th><th>
+ Health (api)
+
+ </th><th>
+ Health (dhcp)
+
+ </th><th>
+ vPing (ssh)
+
+ </th><th>
+ vPing (userdata)
+
+ </th><th>
+ Tempest (smoke)
+
+ </th><th>
+ Rally (smoke)
+
+ </th><th>
+ Refstack
+
+ </th><th>
+ SNAPS
+
+ </th><th>
+ Promise
+
+ </th><th>
+ Doctor
+
+ </th><th>
+ Parser
+
+ </th><th>
+ Domino
+
+ </th>
+ </tr>
+ <tr class="tr-weather-weather">
+ <td><img src="../../img/weather-clear.png"></td><td><img src="../../img/weather-clear.png"></td><td><img src="../../img/weather-storm.png"></td><td><img src="../../img/weather-storm.png"></td><td><img src="../../img/weather-storm.png"></td><td><img src="../../img/weather-storm.png"></td><td><img src="../../img/weather-storm.png"></td><td><img src="../../img/weather-storm.png"></td><td><img src="../../img/weather-storm.png"></td><td><img src="../../img/weather-storm.png"></td><td><img src="../../img/weather-storm.png"></td><td><img src="../../img/weather-storm.png"></td><td><img src="../../img/weather-storm.png"></td>
+ </tr>
+ </table>
+ </div>
+ </div><div class="scenario-part">
+ <div class="page-header">
+ <h3><span class="glyphicon glyphicon-chevron-right"> <b>os-odl_l2-sfc-noha</b></h3>
+ </div>
+ <div class="panel panel-default">
+ <div class="panel-heading">
+ <span class="panel-header-item">
+ </span>
+ </div>
+ <table class="table">
+ <tr>
+ <th>
+ Health (connection)
+
+ </th><th>
+ Health (api)
+
+ </th><th>
+ Health (dhcp)
+
+ </th><th>
+ vPing (ssh)
+
+ </th><th>
+ vPing (userdata)
+
+ </th><th>
+ Tempest (smoke)
+
+ </th><th>
+ Rally (smoke)
+
+ </th><th>
+ Refstack
+
+ </th><th>
+ ODL
+
+ </th><th>
+ SNAPS
+
+ </th><th>
+ Promise
+
+ </th><th>
+ Doctor
+
+ </th><th>
+ SFC
+
+ </th><th>
+ Domino
+
+ </th>
+ </tr>
+ <tr class="tr-weather-weather">
+ <td><img src="../../img/weather-clear.png"></td><td><img src="../../img/weather-clear.png"></td><td><img src="../../img/weather-clear.png"></td><td><img src="../../img/weather-clear.png"></td><td><img src="../../img/weather-clear.png"></td><td><img src="../../img/weather-clear.png"></td><td><img src="../../img/weather-clear.png"></td><td><img src="../../img/weather-clear.png"></td><td><img src="../../img/weather-clear.png"></td><td><img src="../../img/weather-clear.png"></td><td><img src="../../img/weather-clear.png"></td><td><img src="../../img/weather-clear.png"></td><td><img src="../../img/weather-overcast.png"></td><td><img src="../../img/weather-clear.png"></td>
+ </tr>
+ </table>
+ </div>
+ </div><div class="scenario-part">
+ <div class="page-header">
+ <h3><span class="glyphicon glyphicon-chevron-right"> <b>os-odl_l3-nofeature-ha</b></h3>
+ </div>
+ <div class="panel panel-default">
+ <div class="panel-heading">
+ <span class="panel-header-item">
+ </span>
+ </div>
+ <table class="table">
+ <tr>
+ <th>
+ Health (connection)
+
+ </th><th>
+ Health (api)
+
+ </th><th>
+ Health (dhcp)
+
+ </th><th>
+ vPing (userdata)
+
+ </th><th>
+ Tempest (smoke)
+
+ </th><th>
+ Rally (smoke)
+
+ </th><th>
+ Refstack
+
+ </th><th>
+ ODL
+
+ </th><th>
+ SNAPS
+
+ </th><th>
+ Promise
+
+ </th><th>
+ Doctor
+
+ </th><th>
+ Parser
+
+ </th><th>
+ Domino
+
+ </th>
+ </tr>
+ <tr class="tr-weather-weather">
+ <td><img src="../../img/weather-clear.png"></td><td><img src="../../img/weather-clear.png"></td><td><img src="../../img/weather-clear.png"></td><td><img src="../../img/weather-clear.png"></td><td><img src="../../img/weather-few-clouds.png"></td><td><img src="../../img/weather-clear.png"></td><td><img src="../../img/weather-few-clouds.png"></td><td><img src="../../img/weather-clear.png"></td><td><img src="../../img/weather-clear.png"></td><td><img src="../../img/weather-clear.png"></td><td><img src="../../img/weather-clear.png"></td><td><img src="../../img/weather-clear.png"></td><td><img src="../../img/weather-clear.png"></td>
+ </tr>
+ </table>
+ </div>
+ </div><div class="scenario-part">
+ <div class="page-header">
+ <h3><span class="glyphicon glyphicon-chevron-right"> <b>os-nosdn-kvm-noha</b></h3>
+ </div>
+ <div class="panel panel-default">
+ <div class="panel-heading">
+ <span class="panel-header-item">
+ </span>
+ </div>
+ <table class="table">
+ <tr>
+ <th>
+ Health (connection)
+
+ </th><th>
+ Health (api)
+
+ </th><th>
+ Health (dhcp)
+
+ </th><th>
+ vPing (ssh)
+
+ </th><th>
+ vPing (userdata)
+
+ </th><th>
+ Tempest (smoke)
+
+ </th><th>
+ Rally (smoke)
+
+ </th><th>
+ Refstack
+
+ </th><th>
+ SNAPS
+
+ </th><th>
+ Promise
+
+ </th><th>
+ Doctor
+
+ </th><th>
+ Domino
+
+ </th>
+ </tr>
+ <tr class="tr-weather-weather">
+ <td><img src="../../img/weather-clear.png"></td><td><img src="../../img/weather-clear.png"></td><td><img src="../../img/weather-clear.png"></td><td><img src="../../img/weather-clear.png"></td><td><img src="../../img/weather-clear.png"></td><td><img src="../../img/weather-clear.png"></td><td><img src="../../img/weather-clear.png"></td><td><img src="../../img/weather-clear.png"></td><td><img src="../../img/weather-clear.png"></td><td><img src="../../img/weather-clear.png"></td><td><img src="../../img/weather-clear.png"></td><td><img src="../../img/weather-clear.png"></td>
+ </tr>
+ </table>
+ </div>
+ </div><div class="scenario-part">
+ <div class="page-header">
+ <h3><span class="glyphicon glyphicon-chevron-right"> <b>os-odl_l3-nofeature-noha</b></h3>
+ </div>
+ <div class="panel panel-default">
+ <div class="panel-heading">
+ <span class="panel-header-item">
+ </span>
+ </div>
+ <table class="table">
+ <tr>
+ <th>
+ Health (connection)
+
+ </th><th>
+ Health (api)
+
+ </th><th>
+ Health (dhcp)
+
+ </th><th>
+ vPing (userdata)
+
+ </th><th>
+ Tempest (smoke)
+
+ </th><th>
+ Rally (smoke)
+
+ </th><th>
+ Refstack
+
+ </th><th>
+ ODL
+
+ </th><th>
+ SNAPS
+
+ </th><th>
+ Promise
+
+ </th><th>
+ Doctor
+
+ </th><th>
+ Domino
+
+ </th>
+ </tr>
+ <tr class="tr-weather-weather">
+ <td><img src="../../img/weather-clear.png"></td><td><img src="../../img/weather-clear.png"></td><td><img src="../../img/weather-clear.png"></td><td><img src="../../img/weather-clear.png"></td><td><img src="../../img/weather-clear.png"></td><td><img src="../../img/weather-clear.png"></td><td><img src="../../img/weather-clear.png"></td><td><img src="../../img/weather-clear.png"></td><td><img src="../../img/weather-clear.png"></td><td><img src="../../img/weather-clear.png"></td><td><img src="../../img/weather-clear.png"></td><td><img src="../../img/weather-clear.png"></td>
+ </tr>
+ </table>
+ </div>
+ </div><div class="scenario-part">
+ <div class="page-header">
+ <h3><span class="glyphicon glyphicon-chevron-right"> <b>os-odl_l2-nofeature-noha</b></h3>
+ </div>
+ <div class="panel panel-default">
+ <div class="panel-heading">
+ <span class="panel-header-item">
+ </span>
+ </div>
+ <table class="table">
+ <tr>
+ <th>
+ Health (connection)
+
+ </th><th>
+ Health (api)
+
+ </th><th>
+ Health (dhcp)
+
+ </th><th>
+ vPing (ssh)
+
+ </th><th>
+ vPing (userdata)
+
+ </th><th>
+ Tempest (smoke)
+
+ </th><th>
+ Rally (smoke)
+
+ </th><th>
+ Refstack
+
+ </th><th>
+ ODL
+
+ </th><th>
+ SNAPS
+
+ </th><th>
+ Promise
+
+ </th><th>
+ Doctor
+
+ </th><th>
+ Domino
+
+ </th>
+ </tr>
+ <tr class="tr-weather-weather">
+ <td><img src="../../img/weather-clear.png"></td><td><img src="../../img/weather-clear.png"></td><td><img src="../../img/weather-clear.png"></td><td><img src="../../img/weather-clear.png"></td><td><img src="../../img/weather-clear.png"></td><td><img src="../../img/weather-few-clouds.png"></td><td><img src="../../img/weather-clear.png"></td><td><img src="../../img/weather-clear.png"></td><td><img src="../../img/weather-clear.png"></td><td><img src="../../img/weather-clear.png"></td><td><img src="../../img/weather-clear.png"></td><td><img src="../../img/weather-clear.png"></td><td><img src="../../img/weather-clear.png"></td>
+ </tr>
+ </table>
+ </div>
+ </div><div class="scenario-part">
+ <div class="page-header">
+ <h3><span class="glyphicon glyphicon-chevron-right"> <b>os-odl_l2-bgpvpn-ha</b></h3>
+ </div>
+ <div class="panel panel-default">
+ <div class="panel-heading">
+ <span class="panel-header-item">
+ </span>
+ </div>
+ <table class="table">
+ <tr>
+ <th>
+ Health (connection)
+
+ </th><th>
+ Health (api)
+
+ </th><th>
+ Health (dhcp)
+
+ </th><th>
+ vPing (ssh)
+
+ </th><th>
+ vPing (userdata)
+
+ </th><th>
+ Tempest (smoke)
+
+ </th><th>
+ Rally (smoke)
+
+ </th><th>
+ Refstack
+
+ </th><th>
+ ODL
+
+ </th><th>
+ SNAPS
+
+ </th><th>
+ Promise
+
+ </th><th>
+ Doctor
+
+ </th><th>
+ bgpvpn
+
+ </th><th>
+ Domino
+
+ </th>
+ </tr>
+ <tr class="tr-weather-weather">
+ <td><img src="../../img/weather-clear.png"></td><td><img src="../../img/weather-clear.png"></td><td><img src="../../img/weather-clear.png"></td><td><img src="../../img/weather-clear.png"></td><td><img src="../../img/weather-clear.png"></td><td><img src="../../img/weather-clear.png"></td><td><img src="../../img/weather-clear.png"></td><td><img src="../../img/weather-few-clouds.png"></td><td><img src="../../img/weather-few-clouds.png"></td><td><img src="../../img/weather-clear.png"></td><td><img src="../../img/weather-clear.png"></td><td><img src="../../img/weather-clear.png"></td><td><img src="../../img/weather-few-clouds.png"></td><td><img src="../../img/weather-clear.png"></td>
+ </tr>
+ </table>
+ </div>
+ </div><div class="scenario-part">
+ <div class="page-header">
+ <h3><span class="glyphicon glyphicon-chevron-right"> <b>os-odl_l2-sfc-ha</b></h3>
+ </div>
+ <div class="panel panel-default">
+ <div class="panel-heading">
+ <span class="panel-header-item">
+ </span>
+ </div>
+ <table class="table">
+ <tr>
+ <th>
+ Health (connection)
+
+ </th><th>
+ Health (api)
+
+ </th><th>
+ Health (dhcp)
+
+ </th><th>
+ vPing (ssh)
+
+ </th><th>
+ vPing (userdata)
+
+ </th><th>
+ Tempest (smoke)
+
+ </th><th>
+ Rally (smoke)
+
+ </th><th>
+ Refstack
+
+ </th><th>
+ ODL
+
+ </th><th>
+ SNAPS
+
+ </th><th>
+ Promise
+
+ </th><th>
+ Doctor
+
+ </th><th>
+ SFC
+
+ </th><th>
+ Parser
+
+ </th><th>
+ Domino
+
+ </th>
+ </tr>
+ <tr class="tr-weather-weather">
+ <td><img src="../../img/weather-clear.png"></td><td><img src="../../img/weather-clear.png"></td><td><img src="../../img/weather-clear.png"></td><td><img src="../../img/weather-clear.png"></td><td><img src="../../img/weather-clear.png"></td><td><img src="../../img/weather-clear.png"></td><td><img src="../../img/weather-clear.png"></td><td><img src="../../img/weather-clear.png"></td><td><img src="../../img/weather-clear.png"></td><td><img src="../../img/weather-clear.png"></td><td><img src="../../img/weather-clear.png"></td><td><img src="../../img/weather-clear.png"></td><td><img src="../../img/weather-clear.png"></td><td><img src="../../img/weather-clear.png"></td><td><img src="../../img/weather-clear.png"></td>
+ </tr>
+ </table>
+ </div>
+ </div><div class="scenario-part">
+ <div class="page-header">
+ <h3><span class="glyphicon glyphicon-chevron-right"> <b>os-nosdn-kvm_ovs_dpdk_bar-noha</b></h3>
+ </div>
+ <div class="panel panel-default">
+ <div class="panel-heading">
+ <span class="panel-header-item">
+ </span>
+ </div>
+ <table class="table">
+ <tr>
+ <th>
+ Health (connection)
+
+ </th><th>
+ Health (api)
+
+ </th><th>
+ Health (dhcp)
+
+ </th><th>
+ vPing (ssh)
+
+ </th><th>
+ vPing (userdata)
+
+ </th><th>
+ Tempest (smoke)
+
+ </th><th>
+ Rally (smoke)
+
+ </th><th>
+ Refstack
+
+ </th><th>
+ SNAPS
+
+ </th><th>
+ Promise
+
+ </th><th>
+ Doctor
+
+ </th><th>
+ Domino
+
+ </th><th>
+ Barometer
+
+ </th>
+ </tr>
+ <tr class="tr-weather-weather">
+ <td><img src="../../img/weather-clear.png"></td><td><img src="../../img/weather-clear.png"></td><td><img src="../../img/weather-clear.png"></td><td><img src="../../img/weather-clear.png"></td><td><img src="../../img/weather-clear.png"></td><td><img src="../../img/weather-clear.png"></td><td><img src="../../img/weather-clear.png"></td><td><img src="../../img/weather-clear.png"></td><td><img src="../../img/weather-clear.png"></td><td><img src="../../img/weather-clear.png"></td><td><img src="../../img/weather-clear.png"></td><td><img src="../../img/weather-clear.png"></td><td><img src="../../img/weather-few-clouds.png"></td>
+ </tr>
+ </table>
+ </div>
+ </div><div class="scenario-part">
+ <div class="page-header">
+ <h3><span class="glyphicon glyphicon-chevron-right"> <b>os-odl_l2-bgpvpn-noha</b></h3>
+ </div>
+ <div class="panel panel-default">
+ <div class="panel-heading">
+ <span class="panel-header-item">
+ </span>
+ </div>
+ <table class="table">
+ <tr>
+ <th>
+ Health (connection)
+
+ </th><th>
+ Health (api)
+
+ </th><th>
+ Health (dhcp)
+
+ </th><th>
+ vPing (ssh)
+
+ </th><th>
+ vPing (userdata)
+
+ </th><th>
+ Tempest (smoke)
+
+ </th><th>
+ Rally (smoke)
+
+ </th><th>
+ Refstack
+
+ </th><th>
+ ODL
+
+ </th><th>
+ SNAPS
+
+ </th><th>
+ Promise
+
+ </th><th>
+ Doctor
+
+ </th><th>
+ bgpvpn
+
+ </th><th>
+ Domino
+
+ </th>
+ </tr>
+ <tr class="tr-weather-weather">
+ <td><img src="../../img/weather-clear.png"></td><td><img src="../../img/weather-clear.png"></td><td><img src="../../img/weather-clear.png"></td><td><img src="../../img/weather-clear.png"></td><td><img src="../../img/weather-clear.png"></td><td><img src="../../img/weather-clear.png"></td><td><img src="../../img/weather-clear.png"></td><td><img src="../../img/weather-clear.png"></td><td><img src="../../img/weather-clear.png"></td><td><img src="../../img/weather-clear.png"></td><td><img src="../../img/weather-clear.png"></td><td><img src="../../img/weather-clear.png"></td><td><img src="../../img/weather-clear.png"></td><td><img src="../../img/weather-clear.png"></td>
+ </tr>
+ </table>
+ </div>
+ </div><div class="scenario-part">
+ <div class="page-header">
+ <h3><span class="glyphicon glyphicon-chevron-right"> <b>os-odl_l2-nofeature-ha</b></h3>
+ </div>
+ <div class="panel panel-default">
+ <div class="panel-heading">
+ <span class="panel-header-item">
+ </span>
+ </div>
+ <table class="table">
+ <tr>
+ <th>
+ Health (connection)
+
+ </th><th>
+ Health (api)
+
+ </th><th>
+ Health (dhcp)
+
+ </th><th>
+ vPing (ssh)
+
+ </th><th>
+ vPing (userdata)
+
+ </th><th>
+ Tempest (smoke)
+
+ </th><th>
+ Rally (smoke)
+
+ </th><th>
+ Refstack
+
+ </th><th>
+ ODL
+
+ </th><th>
+ SNAPS
+
+ </th><th>
+ Promise
+
+ </th><th>
+ Doctor
+
+ </th><th>
+ Parser
+
+ </th><th>
+ Domino
+
+ </th>
+ </tr>
+ <tr class="tr-weather-weather">
+ <td><img src="../../img/weather-clear.png"></td><td><img src="../../img/weather-clear.png"></td><td><img src="../../img/weather-clear.png"></td><td><img src="../../img/weather-clear.png"></td><td><img src="../../img/weather-clear.png"></td><td><img src="../../img/weather-clear.png"></td><td><img src="../../img/weather-clear.png"></td><td><img src="../../img/weather-few-clouds.png"></td><td><img src="../../img/weather-clear.png"></td><td><img src="../../img/weather-few-clouds.png"></td><td><img src="../../img/weather-clear.png"></td><td><img src="../../img/weather-clear.png"></td><td><img src="../../img/weather-clear.png"></td><td><img src="../../img/weather-clear.png"></td>
+ </tr>
+ </table>
+ </div>
+ </div><div class="scenario-part">
+ <div class="page-header">
+ <h3><span class="glyphicon glyphicon-chevron-right"> <b>os-nosdn-nofeature-noha</b></h3>
+ </div>
+ <div class="panel panel-default">
+ <div class="panel-heading">
+ <span class="panel-header-item">
+ </span>
+ </div>
+ <table class="table">
+ <tr>
+ <th>
+ Health (connection)
+
+ </th><th>
+ Health (api)
+
+ </th><th>
+ Health (dhcp)
+
+ </th><th>
+ vPing (ssh)
+
+ </th><th>
+ vPing (userdata)
+
+ </th><th>
+ Tempest (smoke)
+
+ </th><th>
+ Rally (smoke)
+
+ </th><th>
+ Refstack
+
+ </th><th>
+ SNAPS
+
+ </th><th>
+ Promise
+
+ </th><th>
+ Doctor
+
+ </th><th>
+ Domino
+
+ </th>
+ </tr>
+ <tr class="tr-weather-weather">
+ <td><img src="../../img/weather-clear.png"></td><td><img src="../../img/weather-clear.png"></td><td><img src="../../img/weather-clear.png"></td><td><img src="../../img/weather-clear.png"></td><td><img src="../../img/weather-clear.png"></td><td><img src="../../img/weather-clear.png"></td><td><img src="../../img/weather-clear.png"></td><td><img src="../../img/weather-clear.png"></td><td><img src="../../img/weather-clear.png"></td><td><img src="../../img/weather-clear.png"></td><td><img src="../../img/weather-clear.png"></td><td><img src="../../img/weather-clear.png"></td>
+ </tr>
+ </table>
+ </div>
+ </div><div class="scenario-part">
+ <div class="page-header">
+ <h3><span class="glyphicon glyphicon-chevron-right"> <b>os-nosdn-kvm-ha</b></h3>
+ </div>
+ <div class="panel panel-default">
+ <div class="panel-heading">
+ <span class="panel-header-item">
+ </span>
+ </div>
+ <table class="table">
+ <tr>
+ <th>
+ Health (connection)
+
+ </th><th>
+ Health (api)
+
+ </th><th>
+ Health (dhcp)
+
+ </th><th>
+ vPing (ssh)
+
+ </th><th>
+ vPing (userdata)
+
+ </th><th>
+ Tempest (smoke)
+
+ </th><th>
+ Rally (smoke)
+
+ </th><th>
+ Refstack
+
+ </th><th>
+ SNAPS
+
+ </th><th>
+ Promise
+
+ </th><th>
+ Doctor
+
+ </th><th>
+ Parser
+
+ </th><th>
+ Domino
+
+ </th>
+ </tr>
+ <tr class="tr-weather-weather">
+ <td><img src="../../img/weather-clear.png"></td><td><img src="../../img/weather-clear.png"></td><td><img src="../../img/weather-clear.png"></td><td><img src="../../img/weather-clear.png"></td><td><img src="../../img/weather-clear.png"></td><td><img src="../../img/weather-clear.png"></td><td><img src="../../img/weather-clear.png"></td><td><img src="../../img/weather-clear.png"></td><td><img src="../../img/weather-clear.png"></td><td><img src="../../img/weather-clear.png"></td><td><img src="../../img/weather-clear.png"></td><td><img src="../../img/weather-clear.png"></td><td><img src="../../img/weather-clear.png"></td>
+ </tr>
+ </table>
+ </div>
+ </div><div class="scenario-part">
+ <div class="page-header">
+ <h3><span class="glyphicon glyphicon-chevron-right"> <b>os-nosdn-nofeature-ha</b></h3>
+ </div>
+ <div class="panel panel-default">
+ <div class="panel-heading">
+ <span class="panel-header-item">
+ </span>
+ </div>
+ <table class="table">
+ <tr>
+ <th>
+ Health (connection)
+
+ </th><th>
+ Health (api)
+
+ </th><th>
+ Health (dhcp)
+
+ </th><th>
+ vPing (ssh)
+
+ </th><th>
+ vPing (userdata)
+
+ </th><th>
+ Tempest (smoke)
+
+ </th><th>
+ Rally (smoke)
+
+ </th><th>
+ Refstack
+
+ </th><th>
+ SNAPS
+
+ </th><th>
+ Promise
+
+ </th><th>
+ Doctor
+
+ </th><th>
+ Parser
+
+ </th><th>
+ Domino
+
+ </th>
+ </tr>
+ <tr class="tr-weather-weather">
+ <td><img src="../../img/weather-clear.png"></td><td><img src="../../img/weather-clear.png"></td><td><img src="../../img/weather-clear.png"></td><td><img src="../../img/weather-clear.png"></td><td><img src="../../img/weather-clear.png"></td><td><img src="../../img/weather-clear.png"></td><td><img src="../../img/weather-clear.png"></td><td><img src="../../img/weather-clear.png"></td><td><img src="../../img/weather-clear.png"></td><td><img src="../../img/weather-clear.png"></td><td><img src="../../img/weather-clear.png"></td><td><img src="../../img/weather-clear.png"></td><td><img src="../../img/weather-clear.png"></td>
+ </tr>
+ </table>
+ </div>
+ </div>
+ see <a href="https://wiki.opnfv.org/pages/viewpage.action?pageId=6828617">Functest scoring wiki page</a> for details on scenario scoring
+ <div> <br>
+ <a href="./status-fuel.pdf" class="myButtonPdf">Export to PDF</a> <a href="./scenario_history_fuel.txt" class="myButtonCSV">Export to CSV</a>
+ </div>
+ </div>
+ <div class="col-md-1"></div>
+</div>
diff --git a/docs/results/danube/2.0/joid.html b/docs/results/danube/2.0/joid.html
new file mode 100644
index 000000000..e22317477
--- /dev/null
+++ b/docs/results/danube/2.0/joid.html
@@ -0,0 +1,421 @@
+ <html>
+ <head>
+ <meta charset="utf-8">
+ <!-- Bootstrap core CSS -->
+ <link href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.4/css/bootstrap.min.css" rel="stylesheet">
+ <link href="../../js/default.css" rel="stylesheet">
+ <script type="text/javascript" src="http://ajax.googleapis.com/ajax/libs/jquery/1/jquery.min.js"></script>
+ <script type="text/javascript" src="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.4/js/bootstrap.min.js"></script>
+ <script type="text/javascript" src="http://d3js.org/d3.v2.min.js"></script>
+ <script type="text/javascript" src="../../js/gauge.js"></script>
+ <script type="text/javascript" src="../../js/trend.js"></script>
+ <script>
+ function onDocumentReady() {
+ // Gauge management
+ var gaugeScenario1 = gauge('#gaugeScenario1');var gaugeScenario2 = gauge('#gaugeScenario2');var gaugeScenario3 = gauge('#gaugeScenario3');var gaugeScenario4 = gauge('#gaugeScenario4');var gaugeScenario5 = gauge('#gaugeScenario5');
+
+ // assign success rate to the gauge
+ function updateReadings() {
+ gaugeScenario1.update(75.0);gaugeScenario2.update(96.9696969697);gaugeScenario3.update(25.0);gaugeScenario4.update(96.9696969697);gaugeScenario5.update(70.8333333333);
+ }
+ updateReadings();
+ }
+
+ // trend line management
+ d3.csv("./scenario_history.txt", function(data) {
+ // ***************************************
+ // Create the trend line
+ // for scenario os-nosdn-lxd-noha
+ // Filter results
+ var trend1 = data.filter(function(row) {
+ return row["scenario"]=="os-nosdn-lxd-noha" && row["installer"]=="joid";
+ })
+ // Parse the date
+ trend1.forEach(function(d) {
+ d.date = parseDate(d.date);
+ d.score = +d.score
+ });
+ // Draw the trend line
+ var mytrend = trend("#trend_svg1",trend1)
+ // ****************************************// for scenario os-nosdn-nofeature-noha
+ // Filter results
+ var trend2 = data.filter(function(row) {
+ return row["scenario"]=="os-nosdn-nofeature-noha" && row["installer"]=="joid";
+ })
+ // Parse the date
+ trend2.forEach(function(d) {
+ d.date = parseDate(d.date);
+ d.score = +d.score
+ });
+ // Draw the trend line
+ var mytrend = trend("#trend_svg2",trend2)
+ // ****************************************// for scenario os-odl_l2-nofeature-ha
+ // Filter results
+ var trend3 = data.filter(function(row) {
+ return row["scenario"]=="os-odl_l2-nofeature-ha" && row["installer"]=="joid";
+ })
+ // Parse the date
+ trend3.forEach(function(d) {
+ d.date = parseDate(d.date);
+ d.score = +d.score
+ });
+ // Draw the trend line
+ var mytrend = trend("#trend_svg3",trend3)
+ // ****************************************// for scenario os-nosdn-nofeature-ha
+ // Filter results
+ var trend4 = data.filter(function(row) {
+ return row["scenario"]=="os-nosdn-nofeature-ha" && row["installer"]=="joid";
+ })
+ // Parse the date
+ trend4.forEach(function(d) {
+ d.date = parseDate(d.date);
+ d.score = +d.score
+ });
+ // Draw the trend line
+ var mytrend = trend("#trend_svg4",trend4)
+ // ****************************************// for scenario os-nosdn-lxd-ha
+ // Filter results
+ var trend5 = data.filter(function(row) {
+ return row["scenario"]=="os-nosdn-lxd-ha" && row["installer"]=="joid";
+ })
+ // Parse the date
+ trend5.forEach(function(d) {
+ d.date = parseDate(d.date);
+ d.score = +d.score
+ });
+ // Draw the trend line
+ var mytrend = trend("#trend_svg5",trend5)
+ // ****************************************
+ });
+ if ( !window.isLoaded ) {
+ window.addEventListener("load", function() {
+ onDocumentReady();
+ }, false);
+ } else {
+ onDocumentReady();
+ }
+</script>
+<script type="text/javascript">
+$(document).ready(function (){
+ $(".btn-more").click(function() {
+ $(this).hide();
+ $(this).parent().find(".panel-default").show();
+ });
+})
+</script>
+
+ </head>
+ <body>
+ <div class="container">
+ <div class="masthead">
+ <h3 class="text-muted">Functest status page (danube, 2017-05-05 01:45)</h3>
+ <nav>
+ <ul class="nav nav-justified">
+ <li class="active"><a href="http://testresults.opnfv.org/reporting/index.html">Home</a></li>
+ <li><a href="apex.html">Apex</a></li>
+ <li><a href="compass.html">Compass</a></li>
+ <li><a href="fuel.html">Fuel</a></li>
+ <li><a href="joid.html">Joid</a></li>
+ </ul>
+ </nav>
+ </div>
+<div class="row">
+ <div class="col-md-1"></div>
+ <div class="col-md-10">
+ <div class="page-header">
+ <h2>joid</h2>
+ </div>
+
+ <div class="scenario-overview">
+ <div class="panel-heading"><h4><b>List of last scenarios (danube) run over the last 10 days </b></h4></div>
+ <table class="table">
+ <tr>
+ <th width="40%">Scenario</th>
+ <th width="20%">Status</th>
+ <th width="20%">Trend</th>
+ <th width="10%">Score</th>
+ <th width="10%">Iteration</th>
+ </tr>
+ <tr class="tr-ok">
+ <td><a href=https://build.opnfv.org/ci/view/functest/job/functest-joid-baremetal-daily-danube/167/console>os-nosdn-lxd-noha</a></td>
+ <td><div id="gaugeScenario1"></div></td>
+ <td><div id="trend_svg1"></div></td>
+ <td>18/24</td>
+ <td>7</td>
+ </tr><tr class="tr-ok">
+ <td><a href=https://build.opnfv.org/ci/view/functest/job/functest-joid-baremetal-daily-danube/171/console>os-nosdn-nofeature-noha</a></td>
+ <td><div id="gaugeScenario2"></div></td>
+ <td><div id="trend_svg2"></div></td>
+ <td>32/33</td>
+ <td>5</td>
+ </tr><tr class="tr-ok">
+ <td><a href=https://build.opnfv.org/ci/view/functest/job/functest-joid-baremetal-daily-danube/170/console>os-odl_l2-nofeature-ha</a></td>
+ <td><div id="gaugeScenario3"></div></td>
+ <td><div id="trend_svg3"></div></td>
+ <td>9/36</td>
+ <td>8</td>
+ </tr><tr class="tr-ok">
+ <td><a href=https://build.opnfv.org/ci/view/functest/job/functest-joid-baremetal-daily-danube/169/console>os-nosdn-nofeature-ha</a></td>
+ <td><div id="gaugeScenario4"></div></td>
+ <td><div id="trend_svg4"></div></td>
+ <td>32/33</td>
+ <td>5</td>
+ </tr><tr class="tr-ok">
+ <td><a href=https://build.opnfv.org/ci/view/functest/job/functest-joid-baremetal-daily-danube/172/console>os-nosdn-lxd-ha</a></td>
+ <td><div id="gaugeScenario5"></div></td>
+ <td><div id="trend_svg5"></div></td>
+ <td>17/24</td>
+ <td>8</td>
+ </tr>
+ </table>
+ </div>
+
+
+ <div class="scenario-part">
+ <div class="page-header">
+ <h3><span class="glyphicon glyphicon-chevron-right"> <b>os-nosdn-lxd-noha</b></h3>
+ </div>
+ <div class="panel panel-default">
+ <div class="panel-heading">
+ <span class="panel-header-item">
+ </span>
+ </div>
+ <table class="table">
+ <tr>
+ <th>
+ Health (connection)
+
+ </th><th>
+ Health (api)
+
+ </th><th>
+ vPing (ssh)
+
+ </th><th>
+ Tempest (smoke)
+
+ </th><th>
+ Rally (smoke)
+
+ </th><th>
+ Refstack
+
+ </th><th>
+ Promise
+
+ </th><th>
+ Domino
+
+ </th>
+ </tr>
+ <tr class="tr-weather-weather">
+ <td><img src="../../img/weather-clear.png"></td><td><img src="../../img/weather-clear.png"></td><td><img src="../../img/weather-clear.png"></td><td><img src="../../img/weather-clear.png"></td><td><img src="../../img/weather-storm.png"></td><td><img src="../../img/weather-storm.png"></td><td><img src="../../img/weather-clear.png"></td><td><img src="../../img/weather-clear.png"></td>
+ </tr>
+ </table>
+ </div>
+ </div><div class="scenario-part">
+ <div class="page-header">
+ <h3><span class="glyphicon glyphicon-chevron-right"> <b>os-nosdn-nofeature-noha</b></h3>
+ </div>
+ <div class="panel panel-default">
+ <div class="panel-heading">
+ <span class="panel-header-item">
+ </span>
+ </div>
+ <table class="table">
+ <tr>
+ <th>
+ Health (connection)
+
+ </th><th>
+ Health (api)
+
+ </th><th>
+ Health (dhcp)
+
+ </th><th>
+ vPing (ssh)
+
+ </th><th>
+ vPing (userdata)
+
+ </th><th>
+ Tempest (smoke)
+
+ </th><th>
+ Rally (smoke)
+
+ </th><th>
+ Refstack
+
+ </th><th>
+ SNAPS
+
+ </th><th>
+ Promise
+
+ </th><th>
+ Domino
+
+ </th>
+ </tr>
+ <tr class="tr-weather-weather">
+ <td><img src="../../img/weather-clear.png"></td><td><img src="../../img/weather-clear.png"></td><td><img src="../../img/weather-clear.png"></td><td><img src="../../img/weather-clear.png"></td><td><img src="../../img/weather-clear.png"></td><td><img src="../../img/weather-clear.png"></td><td><img src="../../img/weather-clear.png"></td><td><img src="../../img/weather-clear.png"></td><td><img src="../../img/weather-few-clouds.png"></td><td><img src="../../img/weather-clear.png"></td><td><img src="../../img/weather-clear.png"></td>
+ </tr>
+ </table>
+ </div>
+ </div><div class="scenario-part">
+ <div class="page-header">
+ <h3><span class="glyphicon glyphicon-chevron-right"> <b>os-odl_l2-nofeature-ha</b></h3>
+ </div>
+ <div class="panel panel-default">
+ <div class="panel-heading">
+ <span class="panel-header-item">
+ </span>
+ </div>
+ <table class="table">
+ <tr>
+ <th>
+ Health (connection)
+
+ </th><th>
+ Health (api)
+
+ </th><th>
+ Health (dhcp)
+
+ </th><th>
+ vPing (ssh)
+
+ </th><th>
+ vPing (userdata)
+
+ </th><th>
+ Tempest (smoke)
+
+ </th><th>
+ Rally (smoke)
+
+ </th><th>
+ Refstack
+
+ </th><th>
+ ODL
+
+ </th><th>
+ SNAPS
+
+ </th><th>
+ Promise
+
+ </th><th>
+ Domino
+
+ </th>
+ </tr>
+ <tr class="tr-weather-weather">
+ <td><img src="../../img/weather-clear.png"></td><td><img src="../../img/weather-clear.png"></td><td><img src="../../img/weather-clear.png"></td><td><img src="../../img/weather-storm.png"></td><td><img src="../../img/weather-storm.png"></td><td><img src="../../img/weather-storm.png"></td><td><img src="../../img/weather-storm.png"></td><td><img src="../../img/weather-storm.png"></td><td><img src="../../img/weather-storm.png"></td><td><img src="../../img/weather-storm.png"></td><td><img src="../../img/weather-storm.png"></td><td><img src="../../img/weather-storm.png"></td>
+ </tr>
+ </table>
+ </div>
+ </div><div class="scenario-part">
+ <div class="page-header">
+ <h3><span class="glyphicon glyphicon-chevron-right"> <b>os-nosdn-nofeature-ha</b></h3>
+ </div>
+ <div class="panel panel-default">
+ <div class="panel-heading">
+ <span class="panel-header-item">
+ </span>
+ </div>
+ <table class="table">
+ <tr>
+ <th>
+ Health (connection)
+
+ </th><th>
+ Health (api)
+
+ </th><th>
+ Health (dhcp)
+
+ </th><th>
+ vPing (ssh)
+
+ </th><th>
+ vPing (userdata)
+
+ </th><th>
+ Tempest (smoke)
+
+ </th><th>
+ Rally (smoke)
+
+ </th><th>
+ Refstack
+
+ </th><th>
+ SNAPS
+
+ </th><th>
+ Promise
+
+ </th><th>
+ Domino
+
+ </th>
+ </tr>
+ <tr class="tr-weather-weather">
+ <td><img src="../../img/weather-clear.png"></td><td><img src="../../img/weather-clear.png"></td><td><img src="../../img/weather-clear.png"></td><td><img src="../../img/weather-clear.png"></td><td><img src="../../img/weather-clear.png"></td><td><img src="../../img/weather-clear.png"></td><td><img src="../../img/weather-clear.png"></td><td><img src="../../img/weather-clear.png"></td><td><img src="../../img/weather-few-clouds.png"></td><td><img src="../../img/weather-clear.png"></td><td><img src="../../img/weather-clear.png"></td>
+ </tr>
+ </table>
+ </div>
+ </div><div class="scenario-part">
+ <div class="page-header">
+ <h3><span class="glyphicon glyphicon-chevron-right"> <b>os-nosdn-lxd-ha</b></h3>
+ </div>
+ <div class="panel panel-default">
+ <div class="panel-heading">
+ <span class="panel-header-item">
+ </span>
+ </div>
+ <table class="table">
+ <tr>
+ <th>
+ Health (connection)
+
+ </th><th>
+ Health (api)
+
+ </th><th>
+ vPing (ssh)
+
+ </th><th>
+ Tempest (smoke)
+
+ </th><th>
+ Rally (smoke)
+
+ </th><th>
+ Refstack
+
+ </th><th>
+ Promise
+
+ </th><th>
+ Domino
+
+ </th>
+ </tr>
+ <tr class="tr-weather-weather">
+ <td><img src="../../img/weather-clear.png"></td><td><img src="../../img/weather-few-clouds.png"></td><td><img src="../../img/weather-clear.png"></td><td><img src="../../img/weather-clear.png"></td><td><img src="../../img/weather-storm.png"></td><td><img src="../../img/weather-storm.png"></td><td><img src="../../img/weather-clear.png"></td><td><img src="../../img/weather-clear.png"></td>
+ </tr>
+ </table>
+ </div>
+ </div>
+ see <a href="https://wiki.opnfv.org/pages/viewpage.action?pageId=6828617">Functest scoring wiki page</a> for details on scenario scoring
+ <div> <br>
+ <a href="./status-joid.pdf" class="myButtonPdf">Export to PDF</a> <a href="./scenario_history_joid.txt" class="myButtonCSV">Export to CSV</a>
+ </div>
+ </div>
+ <div class="col-md-1"></div>
+</div>
diff --git a/docs/results/danube/2.0/scenario_history.txt b/docs/results/danube/2.0/scenario_history.txt
new file mode 100644
index 000000000..c4ca6aad0
--- /dev/null
+++ b/docs/results/danube/2.0/scenario_history.txt
@@ -0,0 +1,1454 @@
+date,scenario,installer,detail,score
+2017-03-13 10:00,os-odl_l2-fdio-noha,apex,5/33,15.0
+2017-03-13 10:00,os-odl_l2-fdio-ha,apex,1/33,3.0
+2017-03-14 01:45,os-odl_l2-fdio-noha,apex,12/33,36.0
+2017-03-14 01:45,os-odl_l2-fdio-ha,apex,1/33,3.0
+2017-03-15 01:45,os-odl_l2-fdio-noha,apex,29/33,88.0
+2017-03-15 01:45,os-odl_l2-fdio-ha,apex,4/33,12.0
+2017-03-16 01:45,os-odl_l2-fdio-noha,apex,29/36,81.0
+2017-03-16 01:45,os-odl_l2-fdio-ha,apex,13/36,36.0
+2017-03-16 10:23,os-odl_l2-fdio-noha,apex,33/36,92.0
+2017-03-16 10:23,os-odl_l2-fdio-ha,apex,13/36,36.0
+2017-03-17 01:45,os-odl_l2-fdio-noha,apex,33/36,92.0
+2017-03-17 01:45,os-odl_l2-fdio-ha,apex,20/36,56.0
+2017-03-17 07:33,os-odl_l2-fdio-noha,apex,33/36,92.0
+2017-03-17 07:33,os-odl_l2-fdio-ha,apex,20/36,56.0
+2017-03-17 08:49,os-odl_l2-fdio-noha,apex,33/36,92.0
+2017-03-17 08:49,os-nosdn-nofeature-ha,apex,9/33,27.0
+2017-03-17 08:49,os-odl_l2-fdio-ha,apex,20/36,56.0
+2017-03-18 01:45,os-odl-gluon-noha,apex,12/39,31.0
+2017-03-18 01:45,os-odl_l2-fdio-noha,apex,33/36,92.0
+2017-03-18 01:45,os-odl_l3-fdio-noha,apex,15/30,50.0
+2017-03-18 01:45,os-odl_l3-nofeature-ha,apex,8/33,24.0
+2017-03-18 01:45,os-odl_l2-fdio-ha,apex,19/36,53.0
+2017-03-18 01:45,os-odl-bgpvpn-ha,apex,11/39,28.0
+2017-03-18 01:45,os-nosdn-nofeature-ha,apex,11/33,33.0
+2017-03-19 01:45,os-odl_l2-fdio-noha,apex,33/36,92.0
+2017-03-19 01:45,os-odl_l3-fdio-noha,apex,21/30,70.0
+2017-03-19 01:45,os-odl_l3-nofeature-ha,apex,15/33,45.0
+2017-03-19 01:45,os-odl_l2-fdio-ha,apex,19/36,53.0
+2017-03-19 01:45,os-odl-bgpvpn-ha,apex,14/39,36.0
+2017-03-19 01:45,os-nosdn-kvm-ha,apex,11/33,33.0
+2017-03-19 01:45,os-nosdn-nofeature-ha,apex,22/33,67.0
+2017-03-19 01:45,os-odl-gluon-noha,apex,22/39,56.0
+2017-03-19 01:45,os-odl_l2-fdio-noha,apex,33/36,92.0
+2017-03-19 01:45,os-odl_l3-fdio-noha,apex,21/30,70.0
+2017-03-19 01:45,os-odl_l3-nofeature-ha,apex,15/33,45.0
+2017-03-19 01:45,os-odl_l2-fdio-ha,apex,19/36,53.0
+2017-03-19 01:45,os-odl-bgpvpn-ha,apex,14/39,36.0
+2017-03-19 01:45,os-nosdn-kvm-ha,apex,11/33,33.0
+2017-03-19 01:45,os-nosdn-nofeature-ha,apex,22/33,67.0
+2017-03-20 01:45,os-odl-gluon-noha,apex,23/39,59.0
+2017-03-20 01:45,os-odl_l2-fdio-noha,apex,33/36,92.0
+2017-03-20 01:45,os-odl_l3-fdio-noha,apex,21/30,70.0
+2017-03-20 01:45,os-odl_l3-nofeature-ha,apex,15/33,45.0
+2017-03-20 01:45,os-odl_l2-fdio-ha,apex,19/36,53.0
+2017-03-20 01:45,os-nosdn-fdio-ha,apex,2/30,7.0
+2017-03-20 01:45,os-odl-bgpvpn-ha,apex,14/39,36.0
+2017-03-20 01:45,os-nosdn-kvm-ha,apex,12/33,36.0
+2017-03-20 01:45,os-nosdn-nofeature-ha,apex,22/33,67.0
+2017-03-17 01:45,os-nosdn-nofeature-ha,compass,10/30,33.0
+2017-03-17 07:33,os-ocl-nofeature-ha,compass,1/30,3.0
+2017-03-17 07:33,os-nosdn-nofeature-ha,compass,10/30,33.0
+2017-03-17 08:49,os-ocl-nofeature-ha,compass,1/30,3.0
+2017-03-17 08:49,os-nosdn-nofeature-ha,compass,10/30,33.0
+2017-03-18 01:45,os-ocl-nofeature-ha,compass,1/30,3.0
+2017-03-18 01:45,os-odl_l2-nofeature-ha,compass,20/33,61.0
+2017-03-18 01:45,os-nosdn-openo-ha,compass,10/30,33.0
+2017-03-18 01:45,os-odl_l3-nofeature-ha,compass,16/30,53.0
+2017-03-18 01:45,os-nosdn-nofeature-ha,compass,20/30,67.0
+2017-03-19 01:45,os-odl_l3-nofeature-ha,compass,25/30,83.0
+2017-03-19 01:45,os-ocl-nofeature-ha,compass,4/30,13.0
+2017-03-19 01:45,os-onos-nofeature-ha,compass,11/33,33.0
+2017-03-19 01:45,os-odl_l2-nofeature-ha,compass,26/33,79.0
+2017-03-19 01:45,os-nosdn-openo-ha,compass,10/30,33.0
+2017-03-19 01:45,os-nosdn-nofeature-ha,compass,30/30,100.0
+2017-03-20 01:45,os-odl_l3-nofeature-ha,compass,27/30,90.0
+2017-03-20 01:45,os-ocl-nofeature-ha,compass,4/30,13.0
+2017-03-20 01:45,os-onos-nofeature-ha,compass,22/33,67.0
+2017-03-20 01:45,os-odl_l2-nofeature-ha,compass,28/33,85.0
+2017-03-20 01:45,os-nosdn-openo-ha,compass,10/30,33.0
+2017-03-20 01:45,os-nosdn-nofeature-ha,compass,30/30,100.0
+2017-03-19 01:45,os-odl_l2-nofeature-ha,fuel,13/42,31.0
+2017-03-19 01:45,os-odl_l2-nofeature-ha,fuel,13/42,31.0
+2017-03-20 01:45,os-odl_l2-nofeature-ha,fuel,13/42,31.0
+2017-03-20 01:45,os-odl_l2-bgpvpn-ha,fuel,3/42,7.0
+2017-03-16 10:23,os-nosdn-nofeature-ha,joid,10/33,30.0
+2017-03-17 01:45,os-nosdn-lxd-noha,joid,13/24,54.0
+2017-03-17 01:45,os-odl_l2-nofeature-ha,joid,2/36,6.0
+2017-03-17 01:45,os-nosdn-nofeature-ha,joid,10/33,30.0
+2017-03-17 07:33,os-nosdn-lxd-noha,joid,13/24,54.0
+2017-03-17 07:33,os-odl_l2-nofeature-ha,joid,2/36,6.0
+2017-03-17 07:33,os-nosdn-nofeature-ha,joid,11/33,33.0
+2017-03-17 07:33,os-nosdn-nofeature-noha,joid,11/33,33.0
+2017-03-17 08:49,os-nosdn-lxd-noha,joid,13/24,54.0
+2017-03-17 08:49,os-odl_l2-nofeature-ha,joid,2/36,6.0
+2017-03-17 08:49,os-nosdn-nofeature-ha,joid,11/33,33.0
+2017-03-17 08:49,os-nosdn-nofeature-noha,joid,11/33,33.0
+2017-03-18 01:45,os-nosdn-lxd-noha,joid,13/24,54.0
+2017-03-18 01:45,os-odl_l2-nofeature-ha,joid,2/36,6.0
+2017-03-18 01:45,os-nosdn-nofeature-ha,joid,11/33,33.0
+2017-03-18 01:45,os-nosdn-nofeature-noha,joid,11/33,33.0
+2017-03-19 01:45,os-nosdn-lxd-noha,joid,13/24,54.0
+2017-03-19 01:45,os-odl_l2-nofeature-ha,joid,3/36,8.0
+2017-03-19 01:45,os-nosdn-lxd-ha,joid,1/24,4.0
+2017-03-19 01:45,os-nosdn-nofeature-ha,joid,11/33,33.0
+2017-03-19 01:45,os-nosdn-nofeature-noha,joid,22/33,67.0
+2017-03-20 01:45,os-nosdn-lxd-noha,joid,13/24,54.0
+2017-03-20 01:45,os-odl_l2-nofeature-ha,joid,3/36,8.0
+2017-03-20 01:45,os-nosdn-lxd-ha,joid,1/24,4.0
+2017-03-20 01:45,os-nosdn-nofeature-ha,joid,11/33,33.0
+2017-03-20 01:45,os-nosdn-nofeature-noha,joid,22/33,67.0
+2017-03-21 01:45,os-odl-gluon-noha,apex,23/39,59.0
+2017-03-21 01:45,os-odl_l2-fdio-noha,apex,32/36,89.0
+2017-03-21 01:45,os-odl_l3-fdio-noha,apex,27/30,90.0
+2017-03-21 01:45,os-odl_l3-nofeature-ha,apex,15/33,45.0
+2017-03-21 01:45,os-odl_l2-fdio-ha,apex,28/36,78.0
+2017-03-21 01:45,os-nosdn-fdio-ha,apex,4/30,13.0
+2017-03-21 01:45,os-odl-bgpvpn-ha,apex,22/39,56.0
+2017-03-21 01:45,os-nosdn-kvm-ha,apex,22/33,67.0
+2017-03-21 01:45,os-nosdn-nofeature-ha,apex,27/33,82.0
+2017-03-21 01:45,os-odl_l3-nofeature-ha,compass,27/30,90.0
+2017-03-21 01:45,os-ocl-nofeature-ha,compass,7/30,23.0
+2017-03-21 01:45,os-onos-nofeature-ha,compass,31/33,94.0
+2017-03-21 01:45,os-odl_l2-nofeature-ha,compass,30/33,91.0
+2017-03-21 01:45,os-nosdn-openo-ha,compass,20/30,67.0
+2017-03-21 01:45,os-nosdn-nofeature-ha,compass,30/30,100.0
+2017-03-21 01:45,os-odl_l3-nofeature-noha,fuel,11/36,31.0
+2017-03-21 01:45,os-nosdn-nofeature-noha,fuel,12/36,33.0
+2017-03-21 01:45,os-odl_l2-nofeature-noha,fuel,12/39,31.0
+2017-03-21 01:45,os-odl_l2-bgpvpn-ha,fuel,15/42,36.0
+2017-03-21 01:45,os-nosdn-ovs-ha,fuel,26/39,67.0
+2017-03-21 01:45,os-odl_l2-nofeature-ha,fuel,13/42,31.0
+2017-03-21 01:45,os-nosdn-nofeature-ha,fuel,26/39,67.0
+2017-03-21 01:45,os-nosdn-lxd-noha,joid,13/24,54.0
+2017-03-21 01:45,os-odl_l2-nofeature-ha,joid,3/36,8.0
+2017-03-21 01:45,os-nosdn-lxd-ha,joid,1/24,4.0
+2017-03-21 01:45,os-nosdn-nofeature-ha,joid,11/33,33.0
+2017-03-21 01:45,os-nosdn-nofeature-noha,joid,22/33,67.0
+
+2017-03-22 01:45,os-odl-gluon-noha,apex,34/39,87.0
+2017-03-22 01:45,os-odl_l2-fdio-noha,apex,32/36,89.0
+2017-03-22 01:45,os-odl_l3-fdio-noha,apex,27/30,90.0
+2017-03-22 01:45,os-odl_l3-nofeature-ha,apex,22/33,67.0
+2017-03-22 01:45,os-odl_l2-fdio-ha,apex,28/36,78.0
+2017-03-22 01:45,os-nosdn-fdio-ha,apex,4/30,13.0
+2017-03-22 01:45,os-odl-bgpvpn-ha,apex,25/39,64.0
+2017-03-22 01:45,os-nosdn-kvm-ha,apex,23/33,70.0
+2017-03-22 01:45,os-nosdn-nofeature-ha,apex,33/33,100.0
+2017-03-22 01:45,os-odl_l3-nofeature-ha,compass,27/30,90.0
+2017-03-22 01:45,os-ocl-nofeature-ha,compass,7/30,23.0
+2017-03-22 01:45,os-onos-nofeature-ha,compass,31/33,94.0
+2017-03-22 01:45,os-odl_l2-nofeature-ha,compass,29/33,88.0
+2017-03-22 01:45,os-nosdn-openo-ha,compass,29/30,97.0
+2017-03-22 01:45,os-nosdn-nofeature-ha,compass,29/30,97.0
+2017-03-22 01:45,os-nosdn-ovs-noha,fuel,12/36,33.0
+2017-03-22 01:45,os-odl_l3-nofeature-noha,fuel,11/36,31.0
+2017-03-22 01:45,os-odl_l2-bgpvpn-noha,fuel,12/42,29.0
+2017-03-22 01:45,os-odl_l2-sfc-noha,fuel,2/42,5.0
+2017-03-22 01:45,os-odl_l3-nofeature-ha,fuel,19/39,49.0
+2017-03-22 01:45,os-nosdn-nofeature-noha,fuel,24/36,67.0
+2017-03-22 01:45,os-odl_l2-nofeature-noha,fuel,14/39,36.0
+2017-03-22 01:45,os-odl_l2-bgpvpn-ha,fuel,22/42,52.0
+2017-03-22 01:45,os-odl_l2-sfc-ha,fuel,13/45,29.0
+2017-03-22 01:45,os-nosdn-ovs-ha,fuel,26/39,67.0
+2017-03-22 01:45,os-odl_l2-nofeature-ha,fuel,26/42,62.0
+2017-03-22 01:45,os-nosdn-nofeature-ha,fuel,26/39,67.0
+2017-03-22 01:45,os-nosdn-lxd-noha,joid,14/24,58.0
+2017-03-22 01:45,os-odl_l2-nofeature-ha,joid,3/36,8.0
+2017-03-22 01:45,os-nosdn-lxd-ha,joid,2/24,8.0
+2017-03-22 01:45,os-nosdn-nofeature-ha,joid,11/33,33.0
+2017-03-22 01:45,os-nosdn-nofeature-noha,joid,22/33,67.0
+2017-03-23 01:45,os-odl-gluon-noha,apex,34/39,87.0
+2017-03-23 01:45,os-odl_l2-fdio-noha,apex,32/36,89.0
+2017-03-23 01:45,os-odl_l3-fdio-noha,apex,27/30,90.0
+2017-03-23 01:45,os-odl_l3-nofeature-ha,apex,21/33,64.0
+2017-03-23 01:45,os-odl_l2-fdio-ha,apex,28/36,78.0
+2017-03-23 01:45,os-nosdn-fdio-ha,apex,4/30,13.0
+2017-03-23 01:45,os-odl-bgpvpn-ha,apex,25/39,64.0
+2017-03-23 01:45,os-nosdn-kvm-ha,apex,23/33,70.0
+2017-03-23 01:45,os-nosdn-nofeature-ha,apex,32/33,97.0
+2017-03-23 01:45,os-odl_l3-nofeature-ha,compass,25/30,83.0
+2017-03-23 01:45,os-ocl-nofeature-ha,compass,7/30,23.0
+2017-03-23 01:45,os-onos-nofeature-ha,compass,30/33,91.0
+2017-03-23 01:45,os-odl_l2-nofeature-ha,compass,28/33,85.0
+2017-03-23 01:45,os-nosdn-openo-ha,compass,29/30,97.0
+2017-03-23 01:45,os-nosdn-nofeature-ha,compass,28/30,93.0
+2017-03-23 01:45,os-nosdn-kvm_ovs_dpdk-noha,fuel,12/36,33.0
+2017-03-23 01:45,os-nosdn-kvm_ovs_dpdk_bar-ha,fuel,2/42,5.0
+2017-03-23 01:45,os-nosdn-kvm-noha,fuel,12/36,33.0
+2017-03-23 01:45,os-nosdn-ovs-noha,fuel,24/36,67.0
+2017-03-23 01:45,os-odl_l3-nofeature-noha,fuel,22/36,61.0
+2017-03-23 01:45,os-nosdn-kvm_ovs_dpdk-ha,fuel,2/39,5.0
+2017-03-23 01:45,os-odl_l2-bgpvpn-noha,fuel,24/42,57.0
+2017-03-23 01:45,os-odl_l2-sfc-noha,fuel,2/42,5.0
+2017-03-23 01:45,os-odl_l3-nofeature-ha,fuel,19/39,49.0
+2017-03-23 01:45,os-nosdn-kvm-ha,fuel,25/39,64.0
+2017-03-23 01:45,os-nosdn-nofeature-noha,fuel,24/36,67.0
+2017-03-23 01:45,os-odl_l2-nofeature-noha,fuel,26/39,67.0
+2017-03-23 01:45,os-odl_l2-bgpvpn-ha,fuel,25/42,60.0
+2017-03-23 01:45,os-odl_l2-sfc-ha,fuel,13/45,29.0
+2017-03-23 01:45,os-nosdn-kvm_ovs_dpdk_bar-noha,fuel,24/39,62.0
+2017-03-23 01:45,os-nosdn-ovs-ha,fuel,26/39,67.0
+2017-03-23 01:45,os-odl_l2-nofeature-ha,fuel,26/42,62.0
+2017-03-23 01:45,os-nosdn-nofeature-ha,fuel,37/39,95.0
+2017-03-23 01:45,os-nosdn-lxd-noha,joid,20/24,83.0
+2017-03-23 01:45,os-odl_l2-nofeature-ha,joid,7/36,19.0
+2017-03-23 01:45,os-nosdn-lxd-ha,joid,7/24,29.0
+2017-03-23 01:45,os-nosdn-nofeature-ha,joid,11/33,33.0
+2017-03-23 01:45,os-nosdn-nofeature-noha,joid,33/33,100.0
+2017-03-24 01:45,os-odl-gluon-noha,apex,34/39,87.0
+2017-03-24 01:45,os-odl_l2-fdio-noha,apex,32/36,89.0
+2017-03-24 01:45,os-odl_l3-fdio-noha,apex,27/30,90.0
+2017-03-24 01:45,os-odl_l3-nofeature-ha,apex,21/33,64.0
+2017-03-24 01:45,os-odl_l2-fdio-ha,apex,28/36,78.0
+2017-03-24 01:45,os-nosdn-fdio-ha,apex,4/30,13.0
+2017-03-24 01:45,os-odl-bgpvpn-ha,apex,25/39,64.0
+2017-03-24 01:45,os-nosdn-kvm-ha,apex,31/33,94.0
+2017-03-24 01:45,os-nosdn-nofeature-ha,apex,32/33,97.0
+2017-03-24 01:45,os-odl_l3-nofeature-ha,compass,26/30,87.0
+2017-03-24 01:45,os-ocl-nofeature-ha,compass,6/30,20.0
+2017-03-24 01:45,os-onos-nofeature-ha,compass,31/33,94.0
+2017-03-24 01:45,os-odl_l2-nofeature-ha,compass,28/33,85.0
+2017-03-24 01:45,os-nosdn-openo-ha,compass,25/30,83.0
+2017-03-24 01:45,os-nosdn-nofeature-ha,compass,29/30,97.0
+2017-03-24 01:45,os-nosdn-kvm_ovs_dpdk-noha,fuel,24/36,67.0
+2017-03-24 01:45,os-nosdn-kvm_ovs_dpdk_bar-ha,fuel,4/42,10.0
+2017-03-24 01:45,os-nosdn-kvm-noha,fuel,24/36,67.0
+2017-03-24 01:45,os-nosdn-ovs-noha,fuel,24/36,67.0
+2017-03-24 01:45,os-odl_l3-nofeature-noha,fuel,23/36,64.0
+2017-03-24 01:45,os-nosdn-kvm_ovs_dpdk-ha,fuel,4/39,10.0
+2017-03-24 01:45,os-odl_l2-bgpvpn-noha,fuel,24/42,57.0
+2017-03-24 01:45,os-odl_l2-sfc-noha,fuel,14/42,33.0
+2017-03-24 01:45,os-odl_l3-nofeature-ha,fuel,24/39,62.0
+2017-03-24 01:45,os-nosdn-kvm-ha,fuel,25/39,64.0
+2017-03-24 01:45,os-nosdn-nofeature-noha,fuel,36/36,100.0
+2017-03-24 01:45,os-odl_l2-nofeature-noha,fuel,35/39,90.0
+2017-03-24 01:45,os-odl_l2-bgpvpn-ha,fuel,27/42,64.0
+2017-03-24 01:45,os-odl_l2-sfc-ha,fuel,24/45,53.0
+2017-03-24 01:45,os-nosdn-kvm_ovs_dpdk_bar-noha,fuel,24/39,62.0
+2017-03-24 01:45,os-nosdn-ovs-ha,fuel,39/39,100.0
+2017-03-24 01:45,os-odl_l2-nofeature-ha,fuel,26/42,62.0
+2017-03-24 01:45,os-nosdn-nofeature-ha,fuel,38/39,97.0
+2017-03-24 01:45,os-nosdn-lxd-noha,joid,20/24,83.0
+2017-03-24 01:45,os-odl_l2-nofeature-ha,joid,7/36,19.0
+2017-03-24 01:45,os-nosdn-lxd-ha,joid,13/24,54.0
+2017-03-24 01:45,os-nosdn-nofeature-ha,joid,11/33,33.0
+2017-03-24 01:45,os-nosdn-nofeature-noha,joid,32/33,97.0
+2017-03-25 01:45,os-odl-gluon-noha,apex,34/39,87.0
+2017-03-25 01:45,os-odl_l2-fdio-noha,apex,32/36,89.0
+2017-03-25 01:45,os-odl_l3-fdio-noha,apex,27/30,90.0
+2017-03-25 01:45,os-odl_l3-nofeature-ha,apex,23/33,70.0
+2017-03-25 01:45,os-odl_l2-fdio-ha,apex,28/36,78.0
+2017-03-25 01:45,os-nosdn-fdio-ha,apex,4/30,13.0
+2017-03-25 01:45,os-odl-bgpvpn-ha,apex,25/39,64.0
+2017-03-25 01:45,os-nosdn-kvm-ha,apex,31/33,94.0
+2017-03-25 01:45,os-nosdn-nofeature-ha,apex,32/33,97.0
+2017-03-25 01:45,os-odl_l3-nofeature-ha,compass,27/30,90.0
+2017-03-25 01:45,os-ocl-nofeature-ha,compass,6/30,20.0
+2017-03-25 01:45,os-onos-nofeature-ha,compass,27/33,82.0
+2017-03-25 01:45,os-odl_l2-nofeature-ha,compass,28/33,85.0
+2017-03-25 01:45,os-nosdn-openo-ha,compass,25/30,83.0
+2017-03-25 01:45,os-nosdn-nofeature-ha,compass,29/30,97.0
+2017-03-25 01:45,os-nosdn-kvm_ovs_dpdk-noha,fuel,24/36,67.0
+2017-03-25 01:45,os-nosdn-kvm_ovs_dpdk_bar-ha,fuel,4/42,10.0
+2017-03-25 01:45,os-nosdn-kvm-noha,fuel,24/36,67.0
+2017-03-25 01:45,os-nosdn-ovs-noha,fuel,36/36,100.0
+2017-03-25 01:45,os-odl_l3-nofeature-noha,fuel,35/36,97.0
+2017-03-25 01:45,os-nosdn-kvm_ovs_dpdk-ha,fuel,4/39,10.0
+2017-03-25 01:45,os-odl_l2-bgpvpn-noha,fuel,26/42,62.0
+2017-03-25 01:45,os-odl_l2-sfc-noha,fuel,24/42,57.0
+2017-03-25 01:45,os-odl_l3-nofeature-ha,fuel,36/39,92.0
+2017-03-25 01:45,os-nosdn-kvm-ha,fuel,37/39,95.0
+2017-03-25 01:45,os-nosdn-nofeature-noha,fuel,36/36,100.0
+2017-03-25 01:45,os-odl_l2-nofeature-noha,fuel,35/39,90.0
+2017-03-25 01:45,os-odl_l2-bgpvpn-ha,fuel,35/42,83.0
+2017-03-25 01:45,os-odl_l2-sfc-ha,fuel,25/45,56.0
+2017-03-25 01:45,os-nosdn-kvm_ovs_dpdk_bar-noha,fuel,24/39,62.0
+2017-03-25 01:45,os-nosdn-ovs-ha,fuel,39/39,100.0
+2017-03-25 01:45,os-odl_l2-nofeature-ha,fuel,41/42,98.0
+2017-03-25 01:45,os-nosdn-nofeature-ha,fuel,35/39,90.0
+2017-03-25 01:45,os-nosdn-lxd-noha,joid,19/24,79.0
+2017-03-25 01:45,os-odl_l2-nofeature-ha,joid,7/36,19.0
+2017-03-25 01:45,os-nosdn-lxd-ha,joid,13/24,54.0
+2017-03-25 01:45,os-nosdn-nofeature-ha,joid,21/33,64.0
+2017-03-25 01:45,os-nosdn-nofeature-noha,joid,32/33,97.0
+2017-03-26 01:45,os-odl-gluon-noha,apex,34/39,87.0
+2017-03-26 01:45,os-odl_l2-fdio-noha,apex,32/36,89.0
+2017-03-26 01:45,os-odl_l3-fdio-noha,apex,26/30,87.0
+2017-03-26 01:45,os-odl_l3-nofeature-ha,apex,23/33,70.0
+2017-03-26 01:45,os-odl_l2-fdio-ha,apex,22/36,61.0
+2017-03-26 01:45,os-nosdn-fdio-ha,apex,6/30,20.0
+2017-03-26 01:45,os-odl-bgpvpn-ha,apex,25/39,64.0
+2017-03-26 01:45,os-nosdn-kvm-ha,apex,32/33,97.0
+2017-03-26 01:45,os-nosdn-nofeature-ha,apex,32/33,97.0
+2017-03-26 01:45,os-odl_l3-nofeature-ha,compass,26/30,87.0
+2017-03-26 01:45,os-ocl-nofeature-ha,compass,6/30,20.0
+2017-03-26 01:45,os-onos-nofeature-ha,compass,28/33,85.0
+2017-03-26 01:45,os-odl_l2-nofeature-ha,compass,28/33,85.0
+2017-03-26 01:45,os-nosdn-openo-ha,compass,29/30,97.0
+2017-03-26 01:45,os-nosdn-nofeature-ha,compass,29/30,97.0
+2017-03-26 01:45,os-nosdn-kvm_ovs_dpdk-noha,fuel,24/36,67.0
+2017-03-26 01:45,os-nosdn-kvm_ovs_dpdk_bar-ha,fuel,4/42,10.0
+2017-03-26 01:45,os-nosdn-kvm-noha,fuel,24/36,67.0
+2017-03-26 01:45,os-nosdn-ovs-noha,fuel,36/36,100.0
+2017-03-26 01:45,os-odl_l3-nofeature-noha,fuel,35/36,97.0
+2017-03-26 01:45,os-nosdn-kvm_ovs_dpdk-ha,fuel,4/39,10.0
+2017-03-26 01:45,os-odl_l2-bgpvpn-noha,fuel,26/42,62.0
+2017-03-26 01:45,os-odl_l2-sfc-noha,fuel,24/42,57.0
+2017-03-26 01:45,os-odl_l3-nofeature-ha,fuel,36/39,92.0
+2017-03-26 01:45,os-nosdn-kvm-ha,fuel,37/39,95.0
+2017-03-26 01:45,os-nosdn-nofeature-noha,fuel,36/36,100.0
+2017-03-26 01:45,os-odl_l2-nofeature-noha,fuel,36/39,92.0
+2017-03-26 01:45,os-odl_l2-bgpvpn-ha,fuel,35/42,83.0
+2017-03-26 01:45,os-odl_l2-sfc-ha,fuel,25/45,56.0
+2017-03-26 01:45,os-nosdn-kvm_ovs_dpdk_bar-noha,fuel,24/39,62.0
+2017-03-26 01:45,os-nosdn-ovs-ha,fuel,39/39,100.0
+2017-03-26 01:45,os-odl_l2-nofeature-ha,fuel,41/42,98.0
+2017-03-26 01:45,os-nosdn-nofeature-ha,fuel,35/39,90.0
+2017-03-26 01:45,os-nosdn-lxd-noha,joid,19/24,79.0
+2017-03-26 01:45,os-odl_l2-nofeature-ha,joid,9/36,25.0
+2017-03-26 01:45,os-nosdn-lxd-ha,joid,13/24,54.0
+2017-03-26 01:45,os-nosdn-nofeature-ha,joid,22/33,67.0
+2017-03-26 01:45,os-nosdn-nofeature-noha,joid,32/33,97.0
+2017-03-27 01:45,os-odl-gluon-noha,apex,34/39,87.0
+2017-03-27 01:45,os-odl_l2-fdio-noha,apex,18/36,50.0
+2017-03-27 01:45,os-odl_l3-fdio-noha,apex,26/30,87.0
+2017-03-27 01:45,os-odl_l3-nofeature-ha,apex,26/33,79.0
+2017-03-27 01:45,os-odl_l2-fdio-ha,apex,21/36,58.0
+2017-03-27 01:45,os-nosdn-fdio-ha,apex,6/30,20.0
+2017-03-27 01:45,os-odl-bgpvpn-ha,apex,25/39,64.0
+2017-03-27 01:45,os-nosdn-kvm-ha,apex,32/33,97.0
+2017-03-27 01:45,os-nosdn-nofeature-ha,apex,32/33,97.0
+2017-03-27 01:45,os-odl_l3-nofeature-ha,compass,24/30,80.0
+2017-03-27 01:45,os-ocl-nofeature-ha,compass,5/30,17.0
+2017-03-27 01:45,os-onos-nofeature-ha,compass,28/33,85.0
+2017-03-27 01:45,os-odl_l2-nofeature-ha,compass,29/33,88.0
+2017-03-27 01:45,os-nosdn-openo-ha,compass,29/30,97.0
+2017-03-27 01:45,os-nosdn-nofeature-ha,compass,29/30,97.0
+2017-03-27 01:45,os-nosdn-kvm_ovs_dpdk-noha,fuel,24/36,67.0
+2017-03-27 01:45,os-nosdn-kvm_ovs_dpdk_bar-ha,fuel,4/42,10.0
+2017-03-27 01:45,os-nosdn-kvm-noha,fuel,24/36,67.0
+2017-03-27 01:45,os-nosdn-ovs-noha,fuel,36/36,100.0
+2017-03-27 01:45,os-odl_l3-nofeature-noha,fuel,35/36,97.0
+2017-03-27 01:45,os-nosdn-kvm_ovs_dpdk-ha,fuel,4/39,10.0
+2017-03-27 01:45,os-odl_l2-bgpvpn-noha,fuel,26/42,62.0
+2017-03-27 01:45,os-odl_l2-sfc-noha,fuel,24/42,57.0
+2017-03-27 01:45,os-odl_l3-nofeature-ha,fuel,36/39,92.0
+2017-03-27 01:45,os-nosdn-kvm-ha,fuel,37/39,95.0
+2017-03-27 01:45,os-nosdn-nofeature-noha,fuel,36/36,100.0
+2017-03-27 01:45,os-odl_l2-nofeature-noha,fuel,36/39,92.0
+2017-03-27 01:45,os-odl_l2-bgpvpn-ha,fuel,35/42,83.0
+2017-03-27 01:45,os-odl_l2-sfc-ha,fuel,25/45,56.0
+2017-03-27 01:45,os-nosdn-kvm_ovs_dpdk_bar-noha,fuel,24/39,62.0
+2017-03-27 01:45,os-nosdn-ovs-ha,fuel,39/39,100.0
+2017-03-27 01:45,os-odl_l2-nofeature-ha,fuel,41/42,98.0
+2017-03-27 01:45,os-nosdn-nofeature-ha,fuel,35/39,90.0
+2017-03-27 01:45,os-nosdn-lxd-noha,joid,13/24,54.0
+2017-03-27 01:45,os-nosdn-nofeature-noha,joid,32/33,97.0
+2017-03-27 01:45,os-nosdn-lxd-ha,joid,13/24,54.0
+2017-03-27 01:45,os-nosdn-nofeature-ha,joid,21/33,64.0
+2017-03-27 01:45,os-odl_l2-nofeature-ha,joid,9/36,25.0
+2017-03-28 01:45,os-odl-gluon-noha,apex,33/39,85.0
+2017-03-28 01:45,os-odl_l2-fdio-noha,apex,28/36,78.0
+2017-03-28 01:45,os-odl_l3-fdio-noha,apex,26/30,87.0
+2017-03-28 01:45,os-odl_l3-nofeature-ha,apex,26/33,79.0
+2017-03-28 01:45,os-nosdn-kvm-ha,apex,32/33,97.0
+2017-03-28 01:45,os-nosdn-fdio-ha,apex,6/30,20.0
+2017-03-28 01:45,os-odl-bgpvpn-ha,apex,24/39,62.0
+2017-03-28 01:45,os-odl_l2-fdio-ha,apex,20/36,56.0
+2017-03-28 01:45,os-nosdn-nofeature-ha,apex,32/33,97.0
+2017-03-28 01:45,os-odl_l3-nofeature-ha,compass,21/30,70.0
+2017-03-28 01:45,os-ocl-nofeature-ha,compass,5/30,17.0
+2017-03-28 01:45,os-onos-nofeature-ha,compass,28/33,85.0
+2017-03-28 01:45,os-odl_l2-nofeature-ha,compass,28/33,85.0
+2017-03-28 01:45,os-nosdn-openo-ha,compass,30/30,100.0
+2017-03-28 01:45,os-nosdn-nofeature-ha,compass,30/30,100.0
+2017-03-28 01:45,os-nosdn-kvm_ovs_dpdk-noha,fuel,36/36,100.0
+2017-03-28 01:45,os-nosdn-kvm_ovs_dpdk_bar-ha,fuel,6/42,14.0
+2017-03-28 01:45,os-nosdn-kvm-noha,fuel,36/36,100.0
+2017-03-28 01:45,os-nosdn-ovs-noha,fuel,36/36,100.0
+2017-03-28 01:45,os-odl_l3-nofeature-noha,fuel,35/36,97.0
+2017-03-28 01:45,os-nosdn-kvm_ovs_dpdk-ha,fuel,6/39,15.0
+2017-03-28 01:45,os-odl_l2-bgpvpn-noha,fuel,36/42,86.0
+2017-03-28 01:45,os-odl_l2-sfc-noha,fuel,27/42,64.0
+2017-03-28 01:45,os-odl_l3-nofeature-ha,fuel,36/39,92.0
+2017-03-28 01:45,os-nosdn-kvm-ha,fuel,37/39,95.0
+2017-03-28 01:45,os-nosdn-nofeature-noha,fuel,36/36,100.0
+2017-03-28 01:45,os-odl_l2-nofeature-noha,fuel,37/39,95.0
+2017-03-28 01:45,os-odl_l2-bgpvpn-ha,fuel,38/42,90.0
+2017-03-28 01:45,os-odl_l2-sfc-ha,fuel,37/45,82.0
+2017-03-28 01:45,os-nosdn-kvm_ovs_dpdk_bar-noha,fuel,37/39,95.0
+2017-03-28 01:45,os-nosdn-ovs-ha,fuel,38/39,97.0
+2017-03-28 01:45,os-odl_l2-nofeature-ha,fuel,41/42,98.0
+2017-03-28 01:45,os-nosdn-nofeature-ha,fuel,38/39,97.0
+2017-03-28 01:45,os-nosdn-lxd-noha,joid,18/24,75.0
+2017-03-28 01:45,os-nosdn-nofeature-noha,joid,32/33,97.0
+2017-03-28 01:45,os-nosdn-lxd-ha,joid,13/24,54.0
+2017-03-28 01:45,os-nosdn-nofeature-ha,joid,21/33,64.0
+2017-03-28 01:45,os-odl_l2-nofeature-ha,joid,9/36,25.0
+2017-03-28 13:20,os-odl-gluon-noha,apex,30/36,83.0
+2017-03-28 13:20,os-odl_l2-fdio-noha,apex,28/36,78.0
+2017-03-28 13:20,os-odl_l3-fdio-noha,apex,26/30,87.0
+2017-03-28 13:20,os-odl-bgpvpn-ha,apex,22/36,61.0
+2017-03-28 13:20,os-nosdn-kvm-ha,apex,32/33,97.0
+2017-03-28 13:20,os-nosdn-fdio-ha,apex,6/30,20.0
+2017-03-28 13:20,os-odl_l3-nofeature-ha,apex,26/33,79.0
+2017-03-28 13:20,os-odl_l2-fdio-ha,apex,25/36,69.0
+2017-03-28 13:20,os-nosdn-nofeature-ha,apex,32/33,97.0
+2017-03-28 13:20,os-odl_l3-nofeature-ha,compass,21/30,70.0
+2017-03-28 13:20,os-ocl-nofeature-ha,compass,4/30,13.0
+2017-03-28 13:20,os-onos-nofeature-ha,compass,27/33,82.0
+2017-03-28 13:20,os-odl_l2-nofeature-ha,compass,28/33,85.0
+2017-03-28 13:20,os-nosdn-openo-ha,compass,30/30,100.0
+2017-03-28 13:20,os-nosdn-nofeature-ha,compass,29/30,97.0
+2017-03-28 13:20,os-nosdn-kvm_ovs_dpdk-noha,fuel,36/36,100.0
+2017-03-28 13:20,os-nosdn-kvm_ovs_dpdk_bar-ha,fuel,6/42,14.0
+2017-03-28 13:20,os-nosdn-kvm-noha,fuel,36/36,100.0
+2017-03-28 13:20,os-nosdn-ovs-noha,fuel,36/36,100.0
+2017-03-28 13:20,os-odl_l3-nofeature-noha,fuel,35/36,97.0
+2017-03-28 13:20,os-nosdn-kvm_ovs_dpdk-ha,fuel,6/39,15.0
+2017-03-28 13:20,os-odl_l2-bgpvpn-noha,fuel,36/42,86.0
+2017-03-28 13:20,os-odl_l2-sfc-noha,fuel,36/42,86.0
+2017-03-28 13:20,os-odl_l3-nofeature-ha,fuel,36/39,92.0
+2017-03-28 13:20,os-nosdn-kvm-ha,fuel,37/39,95.0
+2017-03-28 13:20,os-nosdn-nofeature-noha,fuel,36/36,100.0
+2017-03-28 13:20,os-odl_l2-nofeature-noha,fuel,37/39,95.0
+2017-03-28 13:20,os-odl_l2-bgpvpn-ha,fuel,38/42,90.0
+2017-03-28 13:20,os-odl_l2-sfc-ha,fuel,37/45,82.0
+2017-03-28 13:20,os-nosdn-kvm_ovs_dpdk_bar-noha,fuel,37/39,95.0
+2017-03-28 13:20,os-nosdn-ovs-ha,fuel,38/39,97.0
+2017-03-28 13:20,os-odl_l2-nofeature-ha,fuel,42/42,100.0
+2017-03-28 13:20,os-nosdn-nofeature-ha,fuel,38/39,97.0
+2017-03-28 13:20,os-nosdn-lxd-noha,joid,18/24,75.0
+2017-03-28 13:20,os-odl_l2-nofeature-ha,joid,9/36,25.0
+2017-03-28 13:20,os-nosdn-nofeature-noha,joid,32/33,97.0
+2017-03-28 13:20,os-nosdn-nofeature-ha,joid,21/33,64.0
+2017-03-28 13:20,os-nosdn-lxd-ha,joid,13/24,54.0
+2017-03-28 13:56,os-odl-gluon-noha,apex,30/36,83.0
+2017-03-28 13:56,os-odl_l2-fdio-noha,apex,30/36,83.0
+2017-03-28 13:56,os-odl_l3-fdio-noha,apex,26/30,87.0
+2017-03-28 13:56,os-odl-bgpvpn-ha,apex,22/36,61.0
+2017-03-28 13:56,os-nosdn-kvm-ha,apex,32/33,97.0
+2017-03-28 13:56,os-nosdn-fdio-ha,apex,6/30,20.0
+2017-03-28 13:56,os-odl_l3-nofeature-ha,apex,26/33,79.0
+2017-03-28 13:56,os-odl_l2-fdio-ha,apex,28/36,78.0
+2017-03-28 13:56,os-nosdn-nofeature-ha,apex,32/33,97.0
+2017-03-28 13:56,os-odl_l3-nofeature-ha,compass,21/30,70.0
+2017-03-28 13:56,os-ocl-nofeature-ha,compass,4/30,13.0
+2017-03-28 13:56,os-onos-nofeature-ha,compass,27/33,82.0
+2017-03-28 13:56,os-odl_l2-nofeature-ha,compass,28/33,85.0
+2017-03-28 13:56,os-nosdn-openo-ha,compass,30/30,100.0
+2017-03-28 13:56,os-nosdn-nofeature-ha,compass,29/30,97.0
+2017-03-28 13:56,os-nosdn-kvm_ovs_dpdk-noha,fuel,36/36,100.0
+2017-03-28 13:56,os-nosdn-kvm_ovs_dpdk_bar-ha,fuel,6/42,14.0
+2017-03-28 13:56,os-nosdn-kvm-noha,fuel,36/36,100.0
+2017-03-28 13:56,os-nosdn-ovs-noha,fuel,36/36,100.0
+2017-03-28 13:56,os-odl_l3-nofeature-noha,fuel,35/36,97.0
+2017-03-28 13:56,os-nosdn-kvm_ovs_dpdk-ha,fuel,6/39,15.0
+2017-03-28 13:56,os-odl_l2-bgpvpn-noha,fuel,36/42,86.0
+2017-03-28 13:56,os-odl_l2-sfc-noha,fuel,36/42,86.0
+2017-03-28 13:56,os-odl_l3-nofeature-ha,fuel,36/39,92.0
+2017-03-28 13:56,os-nosdn-kvm-ha,fuel,37/39,95.0
+2017-03-28 13:56,os-nosdn-nofeature-noha,fuel,36/36,100.0
+2017-03-28 13:56,os-odl_l2-nofeature-noha,fuel,37/39,95.0
+2017-03-28 13:56,os-odl_l2-bgpvpn-ha,fuel,38/42,90.0
+2017-03-28 13:56,os-odl_l2-sfc-ha,fuel,37/45,82.0
+2017-03-28 13:56,os-nosdn-kvm_ovs_dpdk_bar-noha,fuel,37/39,95.0
+2017-03-28 13:56,os-nosdn-ovs-ha,fuel,38/39,97.0
+2017-03-28 13:56,os-odl_l2-nofeature-ha,fuel,42/42,100.0
+2017-03-28 13:56,os-nosdn-nofeature-ha,fuel,38/39,97.0
+2017-03-28 13:56,os-nosdn-lxd-noha,joid,18/24,75.0
+2017-03-28 13:56,os-odl_l2-nofeature-ha,joid,9/36,25.0
+2017-03-28 13:56,os-nosdn-nofeature-noha,joid,32/33,97.0
+2017-03-28 13:56,os-nosdn-nofeature-ha,joid,21/33,64.0
+2017-03-28 13:56,os-nosdn-lxd-ha,joid,13/24,54.0
+2017-03-28 16:16,os-odl-gluon-noha,apex,30/36,83.0
+2017-03-28 16:16,os-odl_l2-fdio-noha,apex,30/36,83.0
+2017-03-28 16:16,os-odl_l3-fdio-noha,apex,26/30,87.0
+2017-03-28 16:16,os-odl-bgpvpn-ha,apex,22/36,61.0
+2017-03-28 16:16,os-nosdn-kvm-ha,apex,32/33,97.0
+2017-03-28 16:16,os-nosdn-fdio-ha,apex,6/30,20.0
+2017-03-28 16:16,os-odl_l3-nofeature-ha,apex,26/33,79.0
+2017-03-28 16:16,os-odl_l2-fdio-ha,apex,28/36,78.0
+2017-03-28 16:16,os-nosdn-nofeature-ha,apex,33/33,100.0
+2017-03-28 16:16,os-odl_l3-nofeature-ha,compass,21/30,70.0
+2017-03-28 16:16,os-ocl-nofeature-ha,compass,4/30,13.0
+2017-03-28 16:16,os-onos-nofeature-ha,compass,27/33,82.0
+2017-03-28 16:16,os-odl_l2-nofeature-ha,compass,28/33,85.0
+2017-03-28 16:16,os-nosdn-openo-ha,compass,29/30,97.0
+2017-03-28 16:16,os-nosdn-nofeature-ha,compass,29/30,97.0
+2017-03-28 16:16,os-nosdn-kvm_ovs_dpdk-noha,fuel,36/36,100.0
+2017-03-28 16:16,os-nosdn-kvm_ovs_dpdk_bar-ha,fuel,6/42,14.0
+2017-03-28 16:16,os-nosdn-kvm-noha,fuel,36/36,100.0
+2017-03-28 16:16,os-nosdn-ovs-noha,fuel,36/36,100.0
+2017-03-28 16:16,os-odl_l3-nofeature-noha,fuel,34/36,94.0
+2017-03-28 16:16,os-nosdn-kvm_ovs_dpdk-ha,fuel,6/39,15.0
+2017-03-28 16:16,os-odl_l2-bgpvpn-noha,fuel,36/42,86.0
+2017-03-28 16:16,os-odl_l2-sfc-noha,fuel,36/42,86.0
+2017-03-28 16:16,os-odl_l3-nofeature-ha,fuel,36/39,92.0
+2017-03-28 16:16,os-nosdn-kvm-ha,fuel,37/39,95.0
+2017-03-28 16:16,os-nosdn-nofeature-noha,fuel,36/36,100.0
+2017-03-28 16:16,os-odl_l2-nofeature-noha,fuel,37/39,95.0
+2017-03-28 16:16,os-odl_l2-bgpvpn-ha,fuel,38/42,90.0
+2017-03-28 16:16,os-odl_l2-sfc-ha,fuel,40/45,89.0
+2017-03-28 16:16,os-nosdn-kvm_ovs_dpdk_bar-noha,fuel,37/39,95.0
+2017-03-28 16:16,os-nosdn-ovs-ha,fuel,38/39,97.0
+2017-03-28 16:16,os-odl_l2-nofeature-ha,fuel,42/42,100.0
+2017-03-28 16:16,os-nosdn-nofeature-ha,fuel,38/39,97.0
+2017-03-28 16:16,os-nosdn-lxd-noha,joid,18/24,75.0
+2017-03-28 16:16,os-odl_l2-nofeature-ha,joid,9/36,25.0
+2017-03-28 16:16,os-nosdn-nofeature-noha,joid,32/33,97.0
+2017-03-28 16:16,os-nosdn-nofeature-ha,joid,32/33,97.0
+2017-03-28 16:16,os-nosdn-lxd-ha,joid,13/24,54.0
+2017-03-29 01:45,os-odl-gluon-noha,apex,30/36,83.0
+2017-03-29 01:45,os-odl_l2-fdio-noha,apex,30/36,83.0
+2017-03-29 01:45,os-odl_l3-fdio-noha,apex,26/30,87.0
+2017-03-29 01:45,os-odl-bgpvpn-ha,apex,22/36,61.0
+2017-03-29 01:45,os-nosdn-kvm-ha,apex,32/33,97.0
+2017-03-29 01:45,os-nosdn-fdio-ha,apex,6/30,20.0
+2017-03-29 01:45,os-odl_l3-nofeature-ha,apex,27/33,82.0
+2017-03-29 01:45,os-odl_l2-fdio-ha,apex,28/36,78.0
+2017-03-29 01:45,os-nosdn-nofeature-ha,apex,33/33,100.0
+2017-03-29 01:45,os-odl_l3-nofeature-ha,compass,21/30,70.0
+2017-03-29 01:45,os-ocl-nofeature-ha,compass,4/30,13.0
+2017-03-29 01:45,os-onos-nofeature-ha,compass,27/33,82.0
+2017-03-29 01:45,os-odl_l2-nofeature-ha,compass,28/33,85.0
+2017-03-29 01:45,os-nosdn-openo-ha,compass,29/30,97.0
+2017-03-29 01:45,os-nosdn-nofeature-ha,compass,29/30,97.0
+2017-03-29 01:45,os-nosdn-kvm_ovs_dpdk-noha,fuel,36/36,100.0
+2017-03-29 01:45,os-nosdn-kvm_ovs_dpdk_bar-ha,fuel,6/42,14.0
+2017-03-29 01:45,os-nosdn-kvm-noha,fuel,36/36,100.0
+2017-03-29 01:45,os-nosdn-ovs-noha,fuel,36/36,100.0
+2017-03-29 01:45,os-nosdn-nofeature-noha,fuel,36/36,100.0
+2017-03-29 01:45,os-nosdn-kvm_ovs_dpdk-ha,fuel,6/39,15.0
+2017-03-29 01:45,os-odl_l2-bgpvpn-noha,fuel,36/42,86.0
+2017-03-29 01:45,os-odl_l2-sfc-noha,fuel,36/42,86.0
+2017-03-29 01:45,os-odl_l3-nofeature-ha,fuel,34/39,87.0
+2017-03-29 01:45,os-nosdn-kvm-ha,fuel,37/39,95.0
+2017-03-29 01:45,os-odl_l3-nofeature-noha,fuel,34/36,94.0
+2017-03-29 01:45,os-odl_l2-nofeature-noha,fuel,36/39,92.0
+2017-03-29 01:45,os-odl_l2-bgpvpn-ha,fuel,38/42,90.0
+2017-03-29 01:45,os-odl_l2-sfc-ha,fuel,40/45,89.0
+2017-03-29 01:45,os-nosdn-kvm_ovs_dpdk_bar-noha,fuel,38/39,97.0
+2017-03-29 01:45,os-odl_l2-nofeature-ha,fuel,42/42,100.0
+2017-03-29 01:45,os-nosdn-ovs-ha,fuel,38/39,97.0
+2017-03-29 01:45,os-nosdn-nofeature-ha,fuel,37/39,95.0
+2017-03-29 01:45,os-nosdn-lxd-noha,joid,17/24,71.0
+2017-03-29 01:45,os-nosdn-nofeature-noha,joid,31/33,94.0
+2017-03-29 01:45,os-odl_l2-nofeature-ha,joid,9/36,25.0
+2017-03-29 01:45,os-nosdn-nofeature-ha,joid,32/33,97.0
+2017-03-29 01:45,os-nosdn-lxd-ha,joid,18/24,75.0
+2017-03-30 01:45,os-nosdn-fdio-noha,apex,15/30,50.0
+2017-03-30 01:45,os-odl-gluon-noha,apex,31/36,86.0
+2017-03-30 01:45,os-odl_l2-fdio-noha,apex,30/36,83.0
+2017-03-30 01:45,os-odl_l3-fdio-noha,apex,26/30,87.0
+2017-03-30 01:45,os-odl-bgpvpn-ha,apex,22/36,61.0
+2017-03-30 01:45,os-nosdn-kvm-ha,apex,32/33,97.0
+2017-03-30 01:45,os-nosdn-fdio-ha,apex,6/30,20.0
+2017-03-30 01:45,os-odl_l3-nofeature-ha,apex,27/33,82.0
+2017-03-30 01:45,os-nosdn-ovs-ha,apex,2/33,6.0
+2017-03-30 01:45,os-odl_l2-fdio-ha,apex,29/36,81.0
+2017-03-30 01:45,os-nosdn-nofeature-ha,apex,33/33,100.0
+2017-03-30 01:45,os-odl_l3-nofeature-ha,compass,21/30,70.0
+2017-03-30 01:45,os-ocl-nofeature-ha,compass,4/30,13.0
+2017-03-30 01:45,os-onos-nofeature-ha,compass,28/33,85.0
+2017-03-30 01:45,os-odl_l2-nofeature-ha,compass,28/33,85.0
+2017-03-30 01:45,os-nosdn-openo-ha,compass,28/30,93.0
+2017-03-30 01:45,os-nosdn-nofeature-ha,compass,29/30,97.0
+2017-03-30 01:45,os-nosdn-kvm_ovs_dpdk-noha,fuel,36/36,100.0
+2017-03-30 01:45,os-nosdn-kvm_ovs_dpdk_bar-ha,fuel,6/42,14.0
+2017-03-30 01:45,os-nosdn-kvm-noha,fuel,36/36,100.0
+2017-03-30 01:45,os-nosdn-ovs-noha,fuel,36/36,100.0
+2017-03-30 01:45,os-nosdn-nofeature-noha,fuel,36/36,100.0
+2017-03-30 01:45,os-nosdn-kvm_ovs_dpdk-ha,fuel,6/39,15.0
+2017-03-30 01:45,os-odl_l2-bgpvpn-noha,fuel,36/42,86.0
+2017-03-30 01:45,os-odl_l2-sfc-noha,fuel,35/42,83.0
+2017-03-30 01:45,os-odl_l3-nofeature-ha,fuel,34/39,87.0
+2017-03-30 01:45,os-nosdn-kvm-ha,fuel,37/39,95.0
+2017-03-30 01:45,os-odl_l3-nofeature-noha,fuel,35/36,97.0
+2017-03-30 01:45,os-odl_l2-nofeature-noha,fuel,36/39,92.0
+2017-03-30 01:45,os-odl_l2-bgpvpn-ha,fuel,38/42,90.0
+2017-03-30 01:45,os-odl_l2-sfc-ha,fuel,42/45,93.0
+2017-03-30 01:45,os-nosdn-kvm_ovs_dpdk_bar-noha,fuel,38/39,97.0
+2017-03-30 01:45,os-odl_l2-nofeature-ha,fuel,42/42,100.0
+2017-03-30 01:45,os-nosdn-ovs-ha,fuel,38/39,97.0
+2017-03-30 01:45,os-nosdn-nofeature-ha,fuel,37/39,95.0
+2017-03-30 01:45,os-nosdn-lxd-noha,joid,17/24,71.0
+2017-03-30 01:45,os-nosdn-nofeature-noha,joid,31/33,94.0
+2017-03-30 01:45,os-odl_l2-nofeature-ha,joid,9/36,25.0
+2017-03-30 01:45,os-nosdn-nofeature-ha,joid,32/33,97.0
+2017-03-30 01:45,os-nosdn-lxd-ha,joid,18/24,75.0
+2017-03-31 01:45,os-nosdn-fdio-noha,apex,15/30,50.0
+2017-03-31 01:45,os-odl-gluon-noha,apex,30/36,83.0
+2017-03-31 01:45,os-odl_l2-fdio-noha,apex,30/36,83.0
+2017-03-31 01:45,os-odl_l3-fdio-noha,apex,20/30,67.0
+2017-03-31 01:45,os-odl-bgpvpn-ha,apex,21/36,58.0
+2017-03-31 01:45,os-nosdn-kvm-ha,apex,32/33,97.0
+2017-03-31 01:45,os-nosdn-fdio-ha,apex,6/30,20.0
+2017-03-31 01:45,os-odl_l3-nofeature-ha,apex,27/33,82.0
+2017-03-31 01:45,os-odl_l3-ovs-ha,apex,2/33,6.0
+2017-03-31 01:45,os-nosdn-ovs-ha,apex,2/33,6.0
+2017-03-31 01:45,os-odl_l2-fdio-ha,apex,29/36,81.0
+2017-03-31 01:45,os-nosdn-nofeature-ha,apex,33/33,100.0
+2017-03-31 01:45,os-odl_l3-nofeature-ha,compass,23/30,77.0
+2017-03-31 01:45,os-ocl-nofeature-ha,compass,3/30,10.0
+2017-03-31 01:45,os-onos-nofeature-ha,compass,28/33,85.0
+2017-03-31 01:45,os-odl_l2-nofeature-ha,compass,28/33,85.0
+2017-03-31 01:45,os-nosdn-openo-ha,compass,28/30,93.0
+2017-03-31 01:45,os-nosdn-nofeature-ha,compass,29/30,97.0
+2017-03-31 01:45,os-nosdn-kvm_ovs_dpdk-noha,fuel,36/36,100.0
+2017-03-31 01:45,os-nosdn-kvm_ovs_dpdk_bar-ha,fuel,6/42,14.0
+2017-03-31 01:45,os-nosdn-kvm-noha,fuel,36/36,100.0
+2017-03-31 01:45,os-nosdn-ovs-noha,fuel,36/36,100.0
+2017-03-31 01:45,os-nosdn-kvm_ovs_dpdk-ha,fuel,6/39,15.0
+2017-03-31 01:45,os-odl_l2-sfc-noha,fuel,35/42,83.0
+2017-03-31 01:45,os-odl_l3-nofeature-ha,fuel,31/39,79.0
+2017-03-31 01:45,os-nosdn-kvm-ha,fuel,37/39,95.0
+2017-03-31 01:45,os-nosdn-nofeature-noha,fuel,36/36,100.0
+2017-03-31 01:45,os-odl_l2-nofeature-noha,fuel,36/39,92.0
+2017-03-31 01:45,os-odl_l2-bgpvpn-ha,fuel,37/42,88.0
+2017-03-31 01:45,os-odl_l2-sfc-ha,fuel,43/45,96.0
+2017-03-31 01:45,os-nosdn-kvm_ovs_dpdk_bar-noha,fuel,39/39,100.0
+2017-03-31 01:45,os-odl_l2-bgpvpn-noha,fuel,37/42,88.0
+2017-03-31 01:45,os-odl_l2-nofeature-ha,fuel,42/42,100.0
+2017-03-31 01:45,os-odl_l3-nofeature-noha,fuel,35/36,97.0
+2017-03-31 01:45,os-nosdn-nofeature-ha,fuel,38/39,97.0
+2017-03-31 01:45,os-nosdn-ovs-ha,fuel,38/39,97.0
+2017-03-31 01:45,os-nosdn-lxd-noha,joid,17/24,71.0
+2017-03-31 01:45,os-nosdn-nofeature-noha,joid,31/33,94.0
+2017-03-31 01:45,os-odl_l2-nofeature-ha,joid,9/36,25.0
+2017-03-31 01:45,os-nosdn-nofeature-ha,joid,32/33,97.0
+2017-03-31 01:45,os-nosdn-lxd-ha,joid,18/24,75.0
+2017-04-01 01:45,os-nosdn-fdio-noha,apex,15/30,50.0
+2017-04-01 01:45,os-odl-gluon-noha,apex,24/36,67.0
+2017-04-01 01:45,os-odl_l2-fdio-noha,apex,30/36,83.0
+2017-04-01 01:45,os-odl_l3-fdio-noha,apex,20/30,67.0
+2017-04-01 01:45,os-odl_l3-nofeature-ha,apex,27/33,82.0
+2017-04-01 01:45,os-nosdn-kvm-ha,apex,32/33,97.0
+2017-04-01 01:45,os-nosdn-fdio-ha,apex,6/30,20.0
+2017-04-01 01:45,os-odl-bgpvpn-ha,apex,21/36,58.0
+2017-04-01 01:45,os-odl_l3-ovs-ha,apex,4/33,12.0
+2017-04-01 01:45,os-nosdn-ovs-ha,apex,2/33,6.0
+2017-04-01 01:45,os-odl_l2-fdio-ha,apex,29/36,81.0
+2017-04-01 01:45,os-nosdn-nofeature-ha,apex,33/33,100.0
+2017-04-01 01:45,os-odl_l3-nofeature-ha,compass,24/30,80.0
+2017-04-01 01:45,os-ocl-nofeature-ha,compass,3/30,10.0
+2017-04-01 01:45,os-onos-nofeature-ha,compass,28/33,85.0
+2017-04-01 01:45,os-odl_l2-nofeature-ha,compass,28/33,85.0
+2017-04-01 01:45,os-nosdn-openo-ha,compass,28/30,93.0
+2017-04-01 01:45,os-nosdn-nofeature-ha,compass,30/30,100.0
+2017-04-01 01:45,os-nosdn-kvm_ovs_dpdk-noha,fuel,36/36,100.0
+2017-04-01 01:45,os-nosdn-kvm_ovs_dpdk_bar-ha,fuel,6/42,14.0
+2017-04-01 01:45,os-nosdn-kvm-noha,fuel,36/36,100.0
+2017-04-01 01:45,os-nosdn-ovs-noha,fuel,36/36,100.0
+2017-04-01 01:45,os-nosdn-kvm_ovs_dpdk-ha,fuel,6/39,15.0
+2017-04-01 01:45,os-odl_l2-sfc-noha,fuel,35/42,83.0
+2017-04-01 01:45,os-odl_l3-nofeature-ha,fuel,32/39,82.0
+2017-04-01 01:45,os-nosdn-kvm-ha,fuel,37/39,95.0
+2017-04-01 01:45,os-odl_l2-nofeature-ha,fuel,39/42,93.0
+2017-04-01 01:45,os-nosdn-nofeature-noha,fuel,36/36,100.0
+2017-04-01 01:45,os-odl_l2-nofeature-noha,fuel,36/39,92.0
+2017-04-01 01:45,os-odl_l2-bgpvpn-ha,fuel,34/42,81.0
+2017-04-01 01:45,os-odl_l3-nofeature-noha,fuel,34/36,94.0
+2017-04-01 01:45,os-nosdn-kvm_ovs_dpdk_bar-noha,fuel,39/39,100.0
+2017-04-01 01:45,os-odl_l2-bgpvpn-noha,fuel,38/42,90.0
+2017-04-01 01:45,os-odl_l2-sfc-ha,fuel,44/45,98.0
+2017-04-01 01:45,os-nosdn-ovs-ha,fuel,39/39,100.0
+2017-04-01 01:45,os-nosdn-nofeature-ha,fuel,37/39,95.0
+2017-04-01 01:45,os-nosdn-lxd-noha,joid,18/24,75.0
+2017-04-01 01:45,os-nosdn-nofeature-noha,joid,32/33,97.0
+2017-04-01 01:45,os-nosdn-lxd-ha,joid,18/24,75.0
+2017-04-01 01:45,os-nosdn-nofeature-ha,joid,32/33,97.0
+2017-04-01 01:45,os-odl_l2-nofeature-ha,joid,9/36,25.0
+2017-04-02 01:45,os-nosdn-fdio-noha,apex,15/30,50.0
+2017-04-02 01:45,os-odl-gluon-noha,apex,24/36,67.0
+2017-04-02 01:45,os-odl_l2-fdio-noha,apex,30/36,83.0
+2017-04-02 01:45,os-odl_l3-fdio-noha,apex,13/30,43.0
+2017-04-02 01:45,os-odl-bgpvpn-ha,apex,21/36,58.0
+2017-04-02 01:45,os-nosdn-kvm-ha,apex,32/33,97.0
+2017-04-02 01:45,os-nosdn-fdio-ha,apex,6/30,20.0
+2017-04-02 01:45,os-odl_l3-nofeature-ha,apex,27/33,82.0
+2017-04-02 01:45,os-odl_l3-ovs-ha,apex,4/33,12.0
+2017-04-02 01:45,os-nosdn-ovs-ha,apex,2/33,6.0
+2017-04-02 01:45,os-odl_l2-fdio-ha,apex,29/36,81.0
+2017-04-02 01:45,os-nosdn-nofeature-ha,apex,33/33,100.0
+2017-04-02 01:45,os-odl_l3-nofeature-ha,compass,24/30,80.0
+2017-04-02 01:45,os-ocl-nofeature-ha,compass,3/30,10.0
+2017-04-02 01:45,os-onos-nofeature-ha,compass,28/33,85.0
+2017-04-02 01:45,os-odl_l2-nofeature-ha,compass,27/33,82.0
+2017-04-02 01:45,os-nosdn-openo-ha,compass,28/30,93.0
+2017-04-02 01:45,os-nosdn-nofeature-ha,compass,30/30,100.0
+2017-04-02 01:45,os-nosdn-kvm-noha,fuel,36/36,100.0
+2017-04-02 01:45,os-nosdn-kvm_ovs_dpdk_bar-ha,fuel,6/42,14.0
+2017-04-02 01:45,os-nosdn-ovs-ha,fuel,39/39,100.0
+2017-04-02 01:45,os-nosdn-kvm_ovs_dpdk_bar-noha,fuel,39/39,100.0
+2017-04-02 01:45,os-nosdn-ovs-noha,fuel,36/36,100.0
+2017-04-02 01:45,os-nosdn-kvm_ovs_dpdk-ha,fuel,6/39,15.0
+2017-04-02 01:45,os-odl_l2-sfc-noha,fuel,35/42,83.0
+2017-04-02 01:45,os-odl_l3-nofeature-ha,fuel,32/39,82.0
+2017-04-02 01:45,os-nosdn-kvm-ha,fuel,37/39,95.0
+2017-04-02 01:45,os-nosdn-nofeature-noha,fuel,36/36,100.0
+2017-04-02 01:45,os-odl_l2-nofeature-noha,fuel,35/39,90.0
+2017-04-02 01:45,os-odl_l2-bgpvpn-ha,fuel,34/42,81.0
+2017-04-02 01:45,os-odl_l2-sfc-ha,fuel,40/45,89.0
+2017-04-02 01:45,os-nosdn-kvm_ovs_dpdk-noha,fuel,36/36,100.0
+2017-04-02 01:45,os-odl_l2-bgpvpn-noha,fuel,38/42,90.0
+2017-04-02 01:45,os-odl_l2-nofeature-ha,fuel,37/42,88.0
+2017-04-02 01:45,os-odl_l3-nofeature-noha,fuel,34/36,94.0
+2017-04-02 01:45,os-nosdn-nofeature-ha,fuel,37/39,95.0
+2017-04-02 01:45,os-odl_l2-nofeature-ha,joid,6/36,17.0
+2017-04-02 01:45,os-nosdn-nofeature-noha,joid,32/33,97.0
+2017-04-02 01:45,os-nosdn-lxd-noha,joid,18/24,75.0
+2017-04-02 01:45,os-nosdn-nofeature-ha,joid,32/33,97.0
+2017-04-02 01:45,os-nosdn-lxd-ha,joid,18/24,75.0
+2017-04-03 01:45,os-nosdn-fdio-noha,apex,15/30,50.0
+2017-04-03 01:45,os-odl-gluon-noha,apex,29/36,81.0
+2017-04-03 01:45,os-odl_l2-fdio-noha,apex,29/36,81.0
+2017-04-03 01:45,os-odl_l3-fdio-noha,apex,13/30,43.0
+2017-04-03 01:45,os-odl_l3-nofeature-ha,apex,27/33,82.0
+2017-04-03 01:45,os-odl_l2-fdio-ha,apex,26/36,72.0
+2017-04-03 01:45,os-nosdn-fdio-ha,apex,6/30,20.0
+2017-04-03 01:45,os-odl-bgpvpn-ha,apex,21/36,58.0
+2017-04-03 01:45,os-odl_l3-ovs-ha,apex,4/33,12.0
+2017-04-03 01:45,os-nosdn-ovs-ha,apex,4/33,12.0
+2017-04-03 01:45,os-nosdn-kvm-ha,apex,33/33,100.0
+2017-04-03 01:45,os-nosdn-nofeature-ha,apex,33/33,100.0
+2017-04-03 01:45,os-odl_l3-nofeature-ha,compass,23/30,77.0
+2017-04-03 01:45,os-ocl-nofeature-ha,compass,3/30,10.0
+2017-04-03 01:45,os-onos-nofeature-ha,compass,28/33,85.0
+2017-04-03 01:45,os-odl_l2-nofeature-ha,compass,27/33,82.0
+2017-04-03 01:45,os-nosdn-openo-ha,compass,29/30,97.0
+2017-04-03 01:45,os-nosdn-nofeature-ha,compass,30/30,100.0
+2017-04-03 01:45,os-nosdn-kvm-noha,fuel,36/36,100.0
+2017-04-03 01:45,os-nosdn-kvm_ovs_dpdk_bar-ha,fuel,6/42,14.0
+2017-04-03 01:45,os-nosdn-ovs-ha,fuel,39/39,100.0
+2017-04-03 01:45,os-nosdn-kvm_ovs_dpdk_bar-noha,fuel,39/39,100.0
+2017-04-03 01:45,os-nosdn-ovs-noha,fuel,36/36,100.0
+2017-04-03 01:45,os-nosdn-kvm_ovs_dpdk-ha,fuel,6/39,15.0
+2017-04-03 01:45,os-odl_l2-nofeature-noha,fuel,35/39,90.0
+2017-04-03 01:45,os-odl_l2-sfc-noha,fuel,35/42,83.0
+2017-04-03 01:45,os-odl_l3-nofeature-ha,fuel,32/39,82.0
+2017-04-03 01:45,os-nosdn-kvm-ha,fuel,37/39,95.0
+2017-04-03 01:45,os-nosdn-nofeature-noha,fuel,36/36,100.0
+2017-04-03 01:45,os-odl_l3-nofeature-noha,fuel,34/36,94.0
+2017-04-03 01:45,os-odl_l2-bgpvpn-ha,fuel,35/42,83.0
+2017-04-03 01:45,os-odl_l2-sfc-ha,fuel,39/45,87.0
+2017-04-03 01:45,os-nosdn-kvm_ovs_dpdk-noha,fuel,36/36,100.0
+2017-04-03 01:45,os-odl_l2-bgpvpn-noha,fuel,39/42,93.0
+2017-04-03 01:45,os-odl_l2-nofeature-ha,fuel,38/42,90.0
+2017-04-03 01:45,os-nosdn-nofeature-ha,fuel,36/39,92.0
+2017-04-03 01:45,os-nosdn-lxd-noha,joid,18/24,75.0
+2017-04-03 01:45,os-nosdn-nofeature-noha,joid,32/33,97.0
+2017-04-03 01:45,os-nosdn-lxd-ha,joid,12/24,50.0
+2017-04-03 01:45,os-nosdn-nofeature-ha,joid,32/33,97.0
+2017-04-03 01:45,os-odl_l2-nofeature-ha,joid,6/36,17.0
+2017-04-04 01:45,os-nosdn-fdio-noha,apex,15/30,50.0
+2017-04-04 01:45,os-odl-gluon-noha,apex,30/36,83.0
+2017-04-04 01:45,os-ovn-nofeature-noha,apex,3/33,9.0
+2017-04-04 01:45,os-odl_l2-fdio-noha,apex,29/36,81.0
+2017-04-04 01:45,os-odl_l3-fdio-noha,apex,6/30,20.0
+2017-04-04 01:45,os-odl_l3-nofeature-ha,apex,26/33,79.0
+2017-04-04 01:45,os-nosdn-kvm-ha,apex,33/33,100.0
+2017-04-04 01:45,os-nosdn-fdio-ha,apex,6/30,20.0
+2017-04-04 01:45,os-odl-bgpvpn-ha,apex,22/36,61.0
+2017-04-04 01:45,os-odl_l3-ovs-ha,apex,4/33,12.0
+2017-04-04 01:45,os-nosdn-ovs-ha,apex,4/33,12.0
+2017-04-04 01:45,os-odl_l2-fdio-ha,apex,26/36,72.0
+2017-04-04 01:45,os-nosdn-nofeature-ha,apex,33/33,100.0
+2017-04-04 01:45,os-odl_l3-nofeature-ha,compass,24/30,80.0
+2017-04-04 01:45,os-ocl-nofeature-ha,compass,3/30,10.0
+2017-04-04 01:45,os-onos-nofeature-ha,compass,28/33,85.0
+2017-04-04 01:45,os-odl_l2-nofeature-ha,compass,27/33,82.0
+2017-04-04 01:45,os-nosdn-openo-ha,compass,29/30,97.0
+2017-04-04 01:45,os-nosdn-nofeature-ha,compass,30/30,100.0
+2017-04-04 01:45,os-nosdn-kvm-noha,fuel,35/36,97.0
+2017-04-04 01:45,os-nosdn-kvm_ovs_dpdk_bar-ha,fuel,6/42,14.0
+2017-04-04 01:45,os-nosdn-ovs-ha,fuel,39/39,100.0
+2017-04-04 01:45,os-nosdn-kvm_ovs_dpdk_bar-noha,fuel,39/39,100.0
+2017-04-04 01:45,os-nosdn-ovs-noha,fuel,36/36,100.0
+2017-04-04 01:45,os-nosdn-kvm_ovs_dpdk-ha,fuel,6/39,15.0
+2017-04-04 01:45,os-odl_l2-sfc-noha,fuel,35/42,83.0
+2017-04-04 01:45,os-odl_l2-sfc-ha,fuel,39/45,87.0
+2017-04-04 01:45,os-nosdn-kvm-ha,fuel,36/39,92.0
+2017-04-04 01:45,os-nosdn-nofeature-noha,fuel,35/36,97.0
+2017-04-04 01:45,os-odl_l2-nofeature-noha,fuel,35/39,90.0
+2017-04-04 01:45,os-odl_l2-bgpvpn-ha,fuel,36/42,86.0
+2017-04-04 01:45,os-odl_l3-nofeature-ha,fuel,34/39,87.0
+2017-04-04 01:45,os-nosdn-kvm_ovs_dpdk-noha,fuel,36/36,100.0
+2017-04-04 01:45,os-odl_l2-bgpvpn-noha,fuel,39/42,93.0
+2017-04-04 01:45,os-odl_l2-nofeature-ha,fuel,38/42,90.0
+2017-04-04 01:45,os-odl_l3-nofeature-noha,fuel,34/36,94.0
+2017-04-04 01:45,os-nosdn-nofeature-ha,fuel,37/39,95.0
+2017-04-04 01:45,os-nosdn-lxd-noha,joid,18/24,75.0
+2017-04-04 01:45,os-nosdn-nofeature-noha,joid,32/33,97.0
+2017-04-04 01:45,os-nosdn-lxd-ha,joid,12/24,50.0
+2017-04-04 01:45,os-nosdn-nofeature-ha,joid,32/33,97.0
+2017-04-04 01:45,os-odl_l2-nofeature-ha,joid,6/36,17.0
+2017-04-05 01:45,os-nosdn-fdio-noha,apex,15/30,50.0
+2017-04-05 01:45,os-odl-gluon-noha,apex,29/36,81.0
+2017-04-05 01:45,os-ovn-nofeature-noha,apex,6/33,18.0
+2017-04-05 01:45,os-odl_l2-fdio-noha,apex,29/36,81.0
+2017-04-05 01:45,os-odl_l3-fdio-noha,apex,6/30,20.0
+2017-04-05 01:45,os-odl-bgpvpn-ha,apex,21/36,58.0
+2017-04-05 01:45,os-nosdn-kvm-ha,apex,33/33,100.0
+2017-04-05 01:45,os-nosdn-fdio-ha,apex,6/30,20.0
+2017-04-05 01:45,os-odl_l3-nofeature-ha,apex,26/33,79.0
+2017-04-05 01:45,os-odl_l3-ovs-ha,apex,6/33,18.0
+2017-04-05 01:45,os-nosdn-ovs-ha,apex,4/33,12.0
+2017-04-05 01:45,os-odl_l2-fdio-ha,apex,28/36,78.0
+2017-04-05 01:45,os-nosdn-nofeature-ha,apex,33/33,100.0
+2017-04-05 01:45,os-odl_l3-nofeature-ha,compass,24/30,80.0
+2017-04-05 01:45,os-ocl-nofeature-ha,compass,3/30,10.0
+2017-04-05 01:45,os-onos-nofeature-ha,compass,28/33,85.0
+2017-04-05 01:45,os-odl_l2-nofeature-ha,compass,28/33,85.0
+2017-04-05 01:45,os-nosdn-openo-ha,compass,29/30,97.0
+2017-04-05 01:45,os-nosdn-nofeature-ha,compass,30/30,100.0
+2017-04-05 01:45,os-nosdn-kvm-noha,fuel,35/36,97.0
+2017-04-05 01:45,os-nosdn-kvm_ovs_dpdk_bar-ha,fuel,6/42,14.0
+2017-04-05 01:45,os-nosdn-ovs-ha,fuel,39/39,100.0
+2017-04-05 01:45,os-nosdn-kvm_ovs_dpdk_bar-noha,fuel,39/39,100.0
+2017-04-05 01:45,os-nosdn-ovs-noha,fuel,36/36,100.0
+2017-04-05 01:45,os-nosdn-kvm_ovs_dpdk-ha,fuel,6/39,15.0
+2017-04-05 01:45,os-odl_l2-sfc-noha,fuel,36/42,86.0
+2017-04-05 01:45,os-odl_l2-sfc-ha,fuel,39/45,87.0
+2017-04-05 01:45,os-nosdn-kvm-ha,fuel,36/39,92.0
+2017-04-05 01:45,os-nosdn-nofeature-noha,fuel,35/36,97.0
+2017-04-05 01:45,os-odl_l2-nofeature-noha,fuel,35/39,90.0
+2017-04-05 01:45,os-odl_l2-bgpvpn-ha,fuel,36/42,86.0
+2017-04-05 01:45,os-odl_l3-nofeature-ha,fuel,35/39,90.0
+2017-04-05 01:45,os-nosdn-kvm_ovs_dpdk-noha,fuel,36/36,100.0
+2017-04-05 01:45,os-odl_l2-bgpvpn-noha,fuel,39/42,93.0
+2017-04-05 01:45,os-odl_l2-nofeature-ha,fuel,37/42,88.0
+2017-04-05 01:45,os-odl_l3-nofeature-noha,fuel,33/36,92.0
+2017-04-05 01:45,os-nosdn-nofeature-ha,fuel,36/39,92.0
+2017-04-05 01:45,os-nosdn-lxd-noha,joid,18/24,75.0
+2017-04-05 01:45,os-nosdn-nofeature-noha,joid,32/33,97.0
+2017-04-05 01:45,os-odl_l2-nofeature-ha,joid,3/36,8.0
+2017-04-05 01:45,os-nosdn-nofeature-ha,joid,32/33,97.0
+2017-04-05 01:45,os-nosdn-lxd-ha,joid,12/24,50.0
+2017-04-06 01:45,os-nosdn-fdio-noha,apex,15/30,50.0
+2017-04-06 01:45,os-odl-gluon-noha,apex,29/36,81.0
+2017-04-06 01:45,os-ovn-nofeature-noha,apex,6/33,18.0
+2017-04-06 01:45,os-odl_l2-fdio-noha,apex,29/36,81.0
+2017-04-06 01:45,os-odl_l3-fdio-noha,apex,4/30,13.0
+2017-04-06 01:45,os-odl-bgpvpn-ha,apex,27/36,75.0
+2017-04-06 01:45,os-odl_l2-fdio-ha,apex,28/36,78.0
+2017-04-06 01:45,os-nosdn-fdio-ha,apex,6/30,20.0
+2017-04-06 01:45,os-odl_l3-nofeature-ha,apex,25/33,76.0
+2017-04-06 01:45,os-odl_l3-ovs-ha,apex,6/33,18.0
+2017-04-06 01:45,os-nosdn-ovs-ha,apex,4/33,12.0
+2017-04-06 01:45,os-nosdn-kvm-ha,apex,22/33,67.0
+2017-04-06 01:45,os-nosdn-nofeature-ha,apex,32/33,97.0
+2017-04-06 01:45,os-odl_l3-nofeature-ha,compass,24/30,80.0
+2017-04-06 01:45,os-ocl-nofeature-ha,compass,3/30,10.0
+2017-04-06 01:45,os-onos-nofeature-ha,compass,28/33,85.0
+2017-04-06 01:45,os-odl_l2-nofeature-ha,compass,29/33,88.0
+2017-04-06 01:45,os-nosdn-openo-ha,compass,29/30,97.0
+2017-04-06 01:45,os-nosdn-nofeature-ha,compass,30/30,100.0
+2017-04-06 01:45,os-nosdn-kvm-noha,fuel,35/36,97.0
+2017-04-06 01:45,os-nosdn-kvm_ovs_dpdk_bar-ha,fuel,6/42,14.0
+2017-04-06 01:45,os-nosdn-ovs-ha,fuel,39/39,100.0
+2017-04-06 01:45,os-nosdn-kvm_ovs_dpdk_bar-noha,fuel,39/39,100.0
+2017-04-06 01:45,os-nosdn-ovs-noha,fuel,36/36,100.0
+2017-04-06 01:45,os-nosdn-kvm_ovs_dpdk-ha,fuel,6/39,15.0
+2017-04-06 01:45,os-odl_l2-sfc-noha,fuel,36/42,86.0
+2017-04-06 01:45,os-odl_l2-sfc-ha,fuel,39/45,87.0
+2017-04-06 01:45,os-nosdn-kvm-ha,fuel,37/39,95.0
+2017-04-06 01:45,os-nosdn-nofeature-noha,fuel,35/36,97.0
+2017-04-06 01:45,os-odl_l2-nofeature-noha,fuel,35/39,90.0
+2017-04-06 01:45,os-odl_l2-bgpvpn-ha,fuel,36/42,86.0
+2017-04-06 01:45,os-odl_l3-nofeature-ha,fuel,35/39,90.0
+2017-04-06 01:45,os-nosdn-kvm_ovs_dpdk-noha,fuel,36/36,100.0
+2017-04-06 01:45,os-odl_l2-bgpvpn-noha,fuel,39/42,93.0
+2017-04-06 01:45,os-odl_l2-nofeature-ha,fuel,38/42,90.0
+2017-04-06 01:45,os-odl_l3-nofeature-noha,fuel,32/36,89.0
+2017-04-06 01:45,os-nosdn-nofeature-ha,fuel,35/39,90.0
+2017-04-06 01:45,os-nosdn-lxd-noha,joid,18/24,75.0
+2017-04-06 01:45,os-nosdn-nofeature-noha,joid,32/33,97.0
+2017-04-06 01:45,os-odl_l2-nofeature-ha,joid,3/36,8.0
+2017-04-06 01:45,os-nosdn-nofeature-ha,joid,32/33,97.0
+2017-04-06 01:45,os-nosdn-lxd-ha,joid,12/24,50.0
+2017-04-07 01:45,os-nosdn-fdio-noha,apex,15/30,50.0
+2017-04-07 01:45,os-odl-gluon-noha,apex,27/36,75.0
+2017-04-07 01:45,os-ovn-nofeature-noha,apex,6/33,18.0
+2017-04-07 01:45,os-odl_l2-fdio-noha,apex,30/36,83.0
+2017-04-07 01:45,os-odl_l3-fdio-noha,apex,6/30,20.0
+2017-04-07 01:45,os-odl-bgpvpn-ha,apex,27/36,75.0
+2017-04-07 01:45,os-odl_l2-fdio-ha,apex,28/36,78.0
+2017-04-07 01:45,os-nosdn-fdio-ha,apex,6/30,20.0
+2017-04-07 01:45,os-odl_l3-nofeature-ha,apex,25/33,76.0
+2017-04-07 01:45,os-odl_l3-ovs-ha,apex,6/33,18.0
+2017-04-07 01:45,os-nosdn-ovs-ha,apex,6/33,18.0
+2017-04-07 01:45,os-nosdn-kvm-ha,apex,32/33,97.0
+2017-04-07 01:45,os-nosdn-nofeature-ha,apex,32/33,97.0
+2017-04-07 01:45,os-odl_l3-nofeature-ha,compass,23/30,77.0
+2017-04-07 01:45,os-ocl-nofeature-ha,compass,3/30,10.0
+2017-04-07 01:45,os-onos-nofeature-ha,compass,28/33,85.0
+2017-04-07 01:45,os-odl_l2-nofeature-ha,compass,29/33,88.0
+2017-04-07 01:45,os-nosdn-openo-ha,compass,29/30,97.0
+2017-04-07 01:45,os-nosdn-nofeature-ha,compass,29/30,97.0
+2017-04-07 01:45,os-nosdn-kvm-noha,fuel,35/36,97.0
+2017-04-07 01:45,os-nosdn-kvm_ovs_dpdk_bar-ha,fuel,6/42,14.0
+2017-04-07 01:45,os-nosdn-ovs-ha,fuel,39/39,100.0
+2017-04-07 01:45,os-nosdn-kvm_ovs_dpdk_bar-noha,fuel,39/39,100.0
+2017-04-07 01:45,os-nosdn-ovs-noha,fuel,36/36,100.0
+2017-04-07 01:45,os-nosdn-kvm_ovs_dpdk-ha,fuel,6/39,15.0
+2017-04-07 01:45,os-odl_l2-nofeature-noha,fuel,33/39,85.0
+2017-04-07 01:45,os-odl_l2-sfc-noha,fuel,36/42,86.0
+2017-04-07 01:45,os-odl_l3-nofeature-ha,fuel,34/39,87.0
+2017-04-07 01:45,os-nosdn-kvm-ha,fuel,37/39,95.0
+2017-04-07 01:45,os-nosdn-nofeature-noha,fuel,35/36,97.0
+2017-04-07 01:45,os-odl_l3-nofeature-noha,fuel,32/36,89.0
+2017-04-07 01:45,os-odl_l2-bgpvpn-ha,fuel,38/42,90.0
+2017-04-07 01:45,os-odl_l2-sfc-ha,fuel,42/45,93.0
+2017-04-07 01:45,os-nosdn-kvm_ovs_dpdk-noha,fuel,36/36,100.0
+2017-04-07 01:45,os-odl_l2-bgpvpn-noha,fuel,39/42,93.0
+2017-04-07 01:45,os-odl_l2-nofeature-ha,fuel,37/42,88.0
+2017-04-07 01:45,os-nosdn-nofeature-ha,fuel,36/39,92.0
+2017-04-07 01:45,os-nosdn-lxd-noha,joid,18/24,75.0
+2017-04-07 01:45,os-nosdn-nofeature-noha,joid,32/33,97.0
+2017-04-07 01:45,os-odl_l2-nofeature-ha,joid,3/36,8.0
+2017-04-07 01:45,os-nosdn-nofeature-ha,joid,32/33,97.0
+2017-04-07 01:45,os-nosdn-lxd-ha,joid,12/24,50.0
+2017-04-08 01:45,os-nosdn-fdio-noha,apex,15/30,50.0
+2017-04-08 01:45,os-odl-gluon-noha,apex,27/36,75.0
+2017-04-08 01:45,os-ovn-nofeature-noha,apex,6/33,18.0
+2017-04-08 01:45,os-odl_l2-fdio-noha,apex,30/36,83.0
+2017-04-08 01:45,os-odl_l3-fdio-noha,apex,6/30,20.0
+2017-04-08 01:45,os-odl_l3-nofeature-ha,apex,18/33,55.0
+2017-04-08 01:45,os-nosdn-kvm-ha,apex,32/33,97.0
+2017-04-08 01:45,os-nosdn-fdio-ha,apex,6/30,20.0
+2017-04-08 01:45,os-odl-bgpvpn-ha,apex,19/36,53.0
+2017-04-08 01:45,os-odl_l3-ovs-ha,apex,6/33,18.0
+2017-04-08 01:45,os-nosdn-ovs-ha,apex,6/33,18.0
+2017-04-08 01:45,os-odl_l2-fdio-ha,apex,27/36,75.0
+2017-04-08 01:45,os-nosdn-nofeature-ha,apex,32/33,97.0
+2017-04-08 01:45,os-odl_l3-nofeature-ha,compass,26/30,87.0
+2017-04-08 01:45,os-ocl-nofeature-ha,compass,3/30,10.0
+2017-04-08 01:45,os-onos-nofeature-ha,compass,28/33,85.0
+2017-04-08 01:45,os-odl_l2-nofeature-ha,compass,29/33,88.0
+2017-04-08 01:45,os-nosdn-openo-ha,compass,29/30,97.0
+2017-04-08 01:45,os-nosdn-nofeature-ha,compass,29/30,97.0
+2017-04-08 01:45,os-nosdn-kvm-noha,fuel,35/36,97.0
+2017-04-08 01:45,os-nosdn-kvm_ovs_dpdk_bar-ha,fuel,6/42,14.0
+2017-04-08 01:45,os-nosdn-ovs-ha,fuel,39/39,100.0
+2017-04-08 01:45,os-nosdn-kvm_ovs_dpdk_bar-noha,fuel,39/39,100.0
+2017-04-08 01:45,os-nosdn-ovs-noha,fuel,36/36,100.0
+2017-04-08 01:45,os-nosdn-kvm_ovs_dpdk-ha,fuel,6/39,15.0
+2017-04-08 01:45,os-odl_l2-sfc-noha,fuel,35/42,83.0
+2017-04-08 01:45,os-odl_l3-nofeature-ha,fuel,35/39,90.0
+2017-04-08 01:45,os-nosdn-kvm-ha,fuel,37/39,95.0
+2017-04-08 01:45,os-nosdn-nofeature-noha,fuel,35/36,97.0
+2017-04-08 01:45,os-odl_l2-nofeature-noha,fuel,33/39,85.0
+2017-04-08 01:45,os-odl_l2-bgpvpn-ha,fuel,37/42,88.0
+2017-04-08 01:45,os-odl_l2-sfc-ha,fuel,42/45,93.0
+2017-04-08 01:45,os-nosdn-kvm_ovs_dpdk-noha,fuel,36/36,100.0
+2017-04-08 01:45,os-odl_l2-bgpvpn-noha,fuel,39/42,93.0
+2017-04-08 01:45,os-odl_l2-nofeature-ha,fuel,37/42,88.0
+2017-04-08 01:45,os-odl_l3-nofeature-noha,fuel,32/36,89.0
+2017-04-08 01:45,os-nosdn-nofeature-ha,fuel,35/39,90.0
+2017-04-08 01:45,os-nosdn-lxd-noha,joid,12/24,50.0
+2017-04-08 01:45,os-nosdn-nofeature-noha,joid,22/33,67.0
+2017-04-08 01:45,os-odl_l2-nofeature-ha,joid,3/36,8.0
+2017-04-08 01:45,os-nosdn-nofeature-ha,joid,32/33,97.0
+2017-04-08 01:45,os-nosdn-lxd-ha,joid,12/24,50.0
+2017-04-09 01:45,os-odl-gluon-noha,apex,18/36,50.0
+2017-04-09 01:45,os-ovn-nofeature-noha,apex,6/33,18.0
+2017-04-09 01:45,os-odl_l2-fdio-noha,apex,22/36,61.0
+2017-04-09 01:45,os-odl_l3-ovs-ha,apex,6/33,18.0
+2017-04-09 01:45,os-odl-bgpvpn-ha,apex,19/36,53.0
+2017-04-09 01:45,os-odl_l2-fdio-ha,apex,27/36,75.0
+2017-04-09 01:45,os-odl_l3-fdio-noha,apex,4/30,13.0
+2017-04-09 01:45,os-nosdn-fdio-ha,apex,6/30,20.0
+2017-04-09 01:45,os-odl_l3-nofeature-ha,apex,18/33,55.0
+2017-04-09 01:45,os-nosdn-ovs-ha,apex,4/33,12.0
+2017-04-09 01:45,os-nosdn-kvm-ha,apex,22/33,67.0
+2017-04-09 01:45,os-nosdn-nofeature-ha,apex,32/33,97.0
+2017-04-09 01:45,os-odl_l3-nofeature-ha,compass,24/30,80.0
+2017-04-09 01:45,os-ocl-nofeature-ha,compass,3/30,10.0
+2017-04-09 01:45,os-onos-nofeature-ha,compass,27/33,82.0
+2017-04-09 01:45,os-odl_l2-nofeature-ha,compass,29/33,88.0
+2017-04-09 01:45,os-nosdn-openo-ha,compass,29/30,97.0
+2017-04-09 01:45,os-nosdn-nofeature-ha,compass,28/30,93.0
+2017-04-09 01:45,os-nosdn-kvm-noha,fuel,36/36,100.0
+2017-04-09 01:45,os-nosdn-kvm_ovs_dpdk_bar-ha,fuel,6/42,14.0
+2017-04-09 01:45,os-nosdn-ovs-ha,fuel,39/39,100.0
+2017-04-09 01:45,os-nosdn-kvm_ovs_dpdk_bar-noha,fuel,39/39,100.0
+2017-04-09 01:45,os-nosdn-ovs-noha,fuel,36/36,100.0
+2017-04-09 01:45,os-nosdn-kvm_ovs_dpdk-ha,fuel,6/39,15.0
+2017-04-09 01:45,os-odl_l2-nofeature-noha,fuel,33/39,85.0
+2017-04-09 01:45,os-odl_l2-sfc-noha,fuel,35/42,83.0
+2017-04-09 01:45,os-odl_l3-nofeature-ha,fuel,34/39,87.0
+2017-04-09 01:45,os-nosdn-kvm-ha,fuel,38/39,97.0
+2017-04-09 01:45,os-nosdn-nofeature-noha,fuel,35/36,97.0
+2017-04-09 01:45,os-odl_l3-nofeature-noha,fuel,33/36,92.0
+2017-04-09 01:45,os-odl_l2-bgpvpn-ha,fuel,37/42,88.0
+2017-04-09 01:45,os-odl_l2-sfc-ha,fuel,40/45,89.0
+2017-04-09 01:45,os-nosdn-kvm_ovs_dpdk-noha,fuel,36/36,100.0
+2017-04-09 01:45,os-odl_l2-bgpvpn-noha,fuel,39/42,93.0
+2017-04-09 01:45,os-odl_l2-nofeature-ha,fuel,39/42,93.0
+2017-04-09 01:45,os-nosdn-nofeature-ha,fuel,36/39,92.0
+2017-04-09 01:45,os-nosdn-lxd-noha,joid,12/24,50.0
+2017-04-09 01:45,os-nosdn-nofeature-noha,joid,22/33,67.0
+2017-04-09 01:45,os-odl_l2-nofeature-ha,joid,3/36,8.0
+2017-04-09 01:45,os-nosdn-nofeature-ha,joid,22/33,67.0
+2017-04-09 01:45,os-nosdn-lxd-ha,joid,12/24,50.0
+2017-04-10 01:45,os-odl-gluon-noha,apex,18/36,50.0
+2017-04-10 01:45,os-ovn-nofeature-noha,apex,6/33,18.0
+2017-04-10 01:45,os-odl_l2-fdio-noha,apex,22/36,61.0
+2017-04-10 01:45,os-odl_l3-ovs-ha,apex,6/33,18.0
+2017-04-10 01:45,os-odl-bgpvpn-ha,apex,19/36,53.0
+2017-04-10 01:45,os-odl_l2-fdio-ha,apex,21/36,58.0
+2017-04-10 01:45,os-odl_l3-fdio-noha,apex,4/30,13.0
+2017-04-10 01:45,os-nosdn-fdio-ha,apex,6/30,20.0
+2017-04-10 01:45,os-odl_l3-nofeature-ha,apex,18/33,55.0
+2017-04-10 01:45,os-nosdn-ovs-ha,apex,4/33,12.0
+2017-04-10 01:45,os-nosdn-kvm-ha,apex,22/33,67.0
+2017-04-10 01:45,os-nosdn-nofeature-ha,apex,22/33,67.0
+2017-04-10 01:45,os-odl_l3-nofeature-ha,compass,24/30,80.0
+2017-04-10 01:45,os-ocl-nofeature-ha,compass,3/30,10.0
+2017-04-10 01:45,os-onos-nofeature-ha,compass,28/33,85.0
+2017-04-10 01:45,os-odl_l2-nofeature-ha,compass,28/33,85.0
+2017-04-10 01:45,os-nosdn-openo-ha,compass,29/30,97.0
+2017-04-10 01:45,os-nosdn-nofeature-ha,compass,28/30,93.0
+2017-04-10 01:45,os-nosdn-kvm-noha,fuel,36/36,100.0
+2017-04-10 01:45,os-nosdn-kvm_ovs_dpdk_bar-ha,fuel,6/42,14.0
+2017-04-10 01:45,os-nosdn-ovs-ha,fuel,39/39,100.0
+2017-04-10 01:45,os-nosdn-kvm_ovs_dpdk_bar-noha,fuel,39/39,100.0
+2017-04-10 01:45,os-nosdn-ovs-noha,fuel,36/36,100.0
+2017-04-10 01:45,os-nosdn-kvm_ovs_dpdk-ha,fuel,6/39,15.0
+2017-04-10 01:45,os-odl_l2-sfc-noha,fuel,32/42,76.0
+2017-04-10 01:45,os-odl_l3-nofeature-ha,fuel,35/39,90.0
+2017-04-10 01:45,os-nosdn-kvm-ha,fuel,38/39,97.0
+2017-04-10 01:45,os-nosdn-nofeature-noha,fuel,36/36,100.0
+2017-04-10 01:45,os-odl_l2-nofeature-noha,fuel,35/39,90.0
+2017-04-10 01:45,os-odl_l2-bgpvpn-ha,fuel,37/42,88.0
+2017-04-10 01:45,os-odl_l2-sfc-ha,fuel,39/45,87.0
+2017-04-10 01:45,os-nosdn-kvm_ovs_dpdk-noha,fuel,36/36,100.0
+2017-04-10 01:45,os-odl_l2-bgpvpn-noha,fuel,39/42,93.0
+2017-04-10 01:45,os-odl_l2-nofeature-ha,fuel,39/42,93.0
+2017-04-10 01:45,os-odl_l3-nofeature-noha,fuel,33/36,92.0
+2017-04-10 01:45,os-nosdn-nofeature-ha,fuel,38/39,97.0
+2017-04-10 01:45,os-nosdn-lxd-noha,joid,12/24,50.0
+2017-04-10 01:45,os-nosdn-nofeature-noha,joid,22/33,67.0
+2017-04-10 01:45,os-odl_l2-nofeature-ha,joid,3/36,8.0
+2017-04-10 01:45,os-nosdn-nofeature-ha,joid,21/33,64.0
+2017-04-10 01:45,os-nosdn-lxd-ha,joid,12/24,50.0
+2017-04-11 01:45,os-odl-gluon-noha,apex,18/36,50.0
+2017-04-11 01:45,os-ovn-nofeature-noha,apex,6/33,18.0
+2017-04-11 01:45,os-odl_l2-fdio-noha,apex,22/36,61.0
+2017-04-11 01:45,os-odl_l3-fdio-noha,apex,4/30,13.0
+2017-04-11 01:45,os-odl-bgpvpn-ha,apex,19/36,53.0
+2017-04-11 01:45,os-odl_l2-fdio-ha,apex,21/36,58.0
+2017-04-11 01:45,os-nosdn-fdio-ha,apex,4/30,13.0
+2017-04-11 01:45,os-odl_l3-nofeature-ha,apex,18/33,55.0
+2017-04-11 01:45,os-odl_l3-ovs-ha,apex,4/33,12.0
+2017-04-11 01:45,os-nosdn-ovs-ha,apex,4/33,12.0
+2017-04-11 01:45,os-nosdn-kvm-ha,apex,22/33,67.0
+2017-04-11 01:45,os-nosdn-nofeature-ha,apex,22/33,67.0
+2017-04-11 01:45,os-odl_l3-nofeature-ha,compass,25/30,83.0
+2017-04-11 01:45,os-ocl-nofeature-ha,compass,3/30,10.0
+2017-04-11 01:45,os-onos-nofeature-ha,compass,29/33,88.0
+2017-04-11 01:45,os-odl_l2-nofeature-ha,compass,30/33,91.0
+2017-04-11 01:45,os-nosdn-openo-ha,compass,29/30,97.0
+2017-04-11 01:45,os-nosdn-nofeature-ha,compass,30/30,100.0
+2017-04-11 01:45,os-nosdn-kvm-noha,fuel,36/36,100.0
+2017-04-11 01:45,os-nosdn-kvm_ovs_dpdk_bar-ha,fuel,6/42,14.0
+2017-04-11 01:45,os-nosdn-ovs-ha,fuel,39/39,100.0
+2017-04-11 01:45,os-nosdn-kvm_ovs_dpdk_bar-noha,fuel,39/39,100.0
+2017-04-11 01:45,os-nosdn-ovs-noha,fuel,36/36,100.0
+2017-04-11 01:45,os-nosdn-kvm_ovs_dpdk-ha,fuel,6/39,15.0
+2017-04-11 01:45,os-odl_l2-sfc-noha,fuel,32/42,76.0
+2017-04-11 01:45,os-odl_l3-nofeature-ha,fuel,34/39,87.0
+2017-04-11 01:45,os-nosdn-kvm-ha,fuel,37/39,95.0
+2017-04-11 01:45,os-nosdn-nofeature-noha,fuel,36/36,100.0
+2017-04-11 01:45,os-odl_l2-nofeature-noha,fuel,35/39,90.0
+2017-04-11 01:45,os-odl_l2-bgpvpn-ha,fuel,36/42,86.0
+2017-04-11 01:45,os-odl_l2-sfc-ha,fuel,39/45,87.0
+2017-04-11 01:45,os-nosdn-kvm_ovs_dpdk-noha,fuel,36/36,100.0
+2017-04-11 01:45,os-odl_l2-bgpvpn-noha,fuel,39/42,93.0
+2017-04-11 01:45,os-odl_l2-nofeature-ha,fuel,38/42,90.0
+2017-04-11 01:45,os-odl_l3-nofeature-noha,fuel,33/36,92.0
+2017-04-11 01:45,os-nosdn-nofeature-ha,fuel,39/39,100.0
+2017-04-11 01:45,os-nosdn-lxd-noha,joid,6/24,25.0
+2017-04-11 01:45,os-nosdn-nofeature-noha,joid,22/33,67.0
+2017-04-11 01:45,os-nosdn-lxd-ha,joid,6/24,25.0
+2017-04-11 01:45,os-nosdn-nofeature-ha,joid,22/33,67.0
+2017-04-11 01:45,os-odl_l2-nofeature-ha,joid,3/36,8.0
+2017-04-12 01:45,os-odl-gluon-noha,apex,18/36,50.0
+2017-04-12 01:45,os-ovn-nofeature-noha,apex,6/33,18.0
+2017-04-12 01:45,os-odl_l2-fdio-noha,apex,22/36,61.0
+2017-04-12 01:45,os-odl_l3-fdio-noha,apex,4/30,13.0
+2017-04-12 01:45,os-odl_l3-nofeature-ha,apex,17/33,52.0
+2017-04-12 01:45,os-nosdn-kvm-ha,apex,22/33,67.0
+2017-04-12 01:45,os-nosdn-fdio-ha,apex,4/30,13.0
+2017-04-12 01:45,os-odl-bgpvpn-ha,apex,19/36,53.0
+2017-04-12 01:45,os-odl_l3-ovs-ha,apex,4/33,12.0
+2017-04-12 01:45,os-nosdn-ovs-ha,apex,4/33,12.0
+2017-04-12 01:45,os-odl_l2-fdio-ha,apex,21/36,58.0
+2017-04-12 01:45,os-nosdn-nofeature-ha,apex,21/33,64.0
+2017-04-12 01:45,os-odl_l3-nofeature-ha,compass,26/30,87.0
+2017-04-12 01:45,os-ocl-nofeature-ha,compass,3/30,10.0
+2017-04-12 01:45,os-onos-nofeature-ha,compass,29/33,88.0
+2017-04-12 01:45,os-odl_l2-nofeature-ha,compass,29/33,88.0
+2017-04-12 01:45,os-nosdn-openo-ha,compass,29/30,97.0
+2017-04-12 01:45,os-nosdn-nofeature-ha,compass,29/30,97.0
+2017-04-12 01:45,os-nosdn-kvm-noha,fuel,35/36,97.0
+2017-04-12 01:45,os-nosdn-kvm_ovs_dpdk_bar-ha,fuel,6/42,14.0
+2017-04-12 01:45,os-nosdn-ovs-ha,fuel,39/39,100.0
+2017-04-12 01:45,os-nosdn-kvm_ovs_dpdk_bar-noha,fuel,39/39,100.0
+2017-04-12 01:45,os-nosdn-ovs-noha,fuel,36/36,100.0
+2017-04-12 01:45,os-nosdn-kvm_ovs_dpdk-ha,fuel,6/39,15.0
+2017-04-12 01:45,os-odl_l2-nofeature-noha,fuel,35/39,90.0
+2017-04-12 01:45,os-odl_l2-sfc-noha,fuel,34/42,81.0
+2017-04-12 01:45,os-odl_l3-nofeature-ha,fuel,34/39,87.0
+2017-04-12 01:45,os-nosdn-kvm-ha,fuel,37/39,95.0
+2017-04-12 01:45,os-nosdn-nofeature-noha,fuel,36/36,100.0
+2017-04-12 01:45,os-odl_l3-nofeature-noha,fuel,33/36,92.0
+2017-04-12 01:45,os-odl_l2-bgpvpn-ha,fuel,36/42,86.0
+2017-04-12 01:45,os-odl_l2-sfc-ha,fuel,39/45,87.0
+2017-04-12 01:45,os-nosdn-kvm_ovs_dpdk-noha,fuel,36/36,100.0
+2017-04-12 01:45,os-odl_l2-bgpvpn-noha,fuel,39/42,93.0
+2017-04-12 01:45,os-odl_l2-nofeature-ha,fuel,38/42,90.0
+2017-04-12 01:45,os-nosdn-nofeature-ha,fuel,39/39,100.0
+2017-04-12 01:45,os-nosdn-lxd-noha,joid,12/24,50.0
+2017-04-12 01:45,os-nosdn-nofeature-noha,joid,11/33,33.0
+2017-04-12 01:45,os-odl_l2-nofeature-ha,joid,1/36,3.0
+2017-04-12 01:45,os-nosdn-nofeature-ha,joid,12/33,36.0
+2017-04-12 01:45,os-nosdn-lxd-ha,joid,6/24,25.0
+2017-04-28 20:23,os-nosdn-fdio-noha,apex,28/30,93.0
+2017-04-28 20:23,os-ovn-nofeature-noha,apex,6/33,18.0
+2017-04-28 20:23,os-odl_l2-fdio-noha,apex,19/36,53.0
+2017-04-28 20:23,os-odl_l3-fdio-noha,apex,24/30,80.0
+2017-04-28 20:23,os-odl_l3-nofeature-ha,apex,16/33,48.0
+2017-04-28 20:23,os-nosdn-kvm-ha,apex,20/33,61.0
+2017-04-28 20:23,os-nosdn-fdio-ha,apex,4/30,13.0
+2017-04-28 20:23,os-odl_l3-ovs-ha,apex,4/33,12.0
+2017-04-28 20:23,os-nosdn-ovs-ha,apex,4/33,12.0
+2017-04-28 20:23,os-odl_l2-fdio-ha,apex,26/36,72.0
+2017-04-28 20:23,os-nosdn-nofeature-ha,apex,20/33,61.0
+2017-04-28 20:23,os-odl_l3-nofeature-ha,compass,25/30,83.0
+2017-04-28 20:23,os-ocl-nofeature-ha,compass,3/30,10.0
+2017-04-28 20:23,os-onos-nofeature-ha,compass,29/33,88.0
+2017-04-28 20:23,os-odl_l2-nofeature-ha,compass,29/33,88.0
+2017-04-28 20:23,os-nosdn-openo-ha,compass,30/30,100.0
+2017-04-28 20:23,os-nosdn-nofeature-ha,compass,29/30,97.0
+2017-04-28 20:23,os-nosdn-kvm-noha,fuel,36/36,100.0
+2017-04-28 20:23,os-nosdn-kvm_ovs_dpdk_bar-ha,fuel,6/42,14.0
+2017-04-28 20:23,os-nosdn-kvm_ovs_dpdk-noha,fuel,36/36,100.0
+2017-04-28 20:23,os-nosdn-ovs-noha,fuel,36/36,100.0
+2017-04-28 20:23,os-nosdn-kvm_ovs_dpdk-ha,fuel,6/39,15.0
+2017-04-28 20:23,os-odl_l2-bgpvpn-noha,fuel,40/42,95.0
+2017-04-28 20:23,os-odl_l2-sfc-noha,fuel,36/42,86.0
+2017-04-28 20:23,os-odl_l3-nofeature-ha,fuel,36/39,92.0
+2017-04-28 20:23,os-nosdn-kvm-ha,fuel,39/39,100.0
+2017-04-28 20:23,os-odl_l3-nofeature-noha,fuel,33/36,92.0
+2017-04-28 20:23,os-odl_l2-nofeature-noha,fuel,34/39,87.0
+2017-04-28 20:23,os-odl_l2-bgpvpn-ha,fuel,37/42,88.0
+2017-04-28 20:23,os-odl_l2-sfc-ha,fuel,41/45,91.0
+2017-04-28 20:23,os-nosdn-kvm_ovs_dpdk_bar-noha,fuel,39/39,100.0
+2017-04-28 20:23,os-nosdn-ovs-ha,fuel,39/39,100.0
+2017-04-28 20:23,os-odl_l2-nofeature-ha,fuel,41/42,98.0
+2017-04-28 20:23,os-nosdn-nofeature-noha,fuel,36/36,100.0
+2017-04-28 20:23,os-nosdn-nofeature-ha,fuel,37/39,95.0
+2017-04-28 20:23,os-nosdn-lxd-noha,joid,11/24,46.0
+2017-04-28 20:23,os-odl_l2-nofeature-ha,joid,8/36,22.0
+2017-04-28 20:23,os-nosdn-lxd-ha,joid,18/24,75.0
+2017-04-28 20:23,os-nosdn-nofeature-ha,joid,29/33,88.0
+2017-04-28 20:23,os-nosdn-nofeature-noha,joid,22/33,67.0
+2017-04-29 01:45,os-nosdn-fdio-noha,apex,28/30,93.0
+2017-04-29 01:45,os-ovn-nofeature-noha,apex,6/33,18.0
+2017-04-29 01:45,os-odl_l2-fdio-noha,apex,19/36,53.0
+2017-04-29 01:45,os-odl_l3-fdio-noha,apex,24/30,80.0
+2017-04-29 01:45,os-odl_l3-nofeature-ha,apex,16/33,48.0
+2017-04-29 01:45,os-nosdn-kvm-ha,apex,20/33,61.0
+2017-04-29 01:45,os-nosdn-fdio-ha,apex,4/30,13.0
+2017-04-29 01:45,os-odl_l3-ovs-ha,apex,4/33,12.0
+2017-04-29 01:45,os-nosdn-ovs-ha,apex,4/33,12.0
+2017-04-29 01:45,os-odl_l2-fdio-ha,apex,30/36,83.0
+2017-04-29 01:45,os-nosdn-nofeature-ha,apex,20/33,61.0
+2017-04-29 01:45,os-odl_l3-nofeature-ha,compass,25/30,83.0
+2017-04-29 01:45,os-ocl-nofeature-ha,compass,3/30,10.0
+2017-04-29 01:45,os-onos-nofeature-ha,compass,29/33,88.0
+2017-04-29 01:45,os-odl_l2-nofeature-ha,compass,29/33,88.0
+2017-04-29 01:45,os-nosdn-openo-ha,compass,30/30,100.0
+2017-04-29 01:45,os-nosdn-nofeature-ha,compass,29/30,97.0
+2017-04-29 01:45,os-nosdn-kvm-noha,fuel,36/36,100.0
+2017-04-29 01:45,os-nosdn-kvm_ovs_dpdk_bar-ha,fuel,6/42,14.0
+2017-04-29 01:45,os-nosdn-ovs-ha,fuel,39/39,100.0
+2017-04-29 01:45,os-nosdn-kvm_ovs_dpdk_bar-noha,fuel,39/39,100.0
+2017-04-29 01:45,os-nosdn-ovs-noha,fuel,36/36,100.0
+2017-04-29 01:45,os-nosdn-kvm_ovs_dpdk-ha,fuel,6/39,15.0
+2017-04-29 01:45,os-odl_l2-sfc-noha,fuel,36/42,86.0
+2017-04-29 01:45,os-odl_l3-nofeature-ha,fuel,36/39,92.0
+2017-04-29 01:45,os-nosdn-kvm-ha,fuel,39/39,100.0
+2017-04-29 01:45,os-nosdn-nofeature-noha,fuel,36/36,100.0
+2017-04-29 01:45,os-odl_l2-nofeature-noha,fuel,34/39,87.0
+2017-04-29 01:45,os-odl_l2-bgpvpn-ha,fuel,37/42,88.0
+2017-04-29 01:45,os-odl_l2-sfc-ha,fuel,41/45,91.0
+2017-04-29 01:45,os-nosdn-kvm_ovs_dpdk-noha,fuel,36/36,100.0
+2017-04-29 01:45,os-odl_l2-bgpvpn-noha,fuel,40/42,95.0
+2017-04-29 01:45,os-odl_l2-nofeature-ha,fuel,41/42,98.0
+2017-04-29 01:45,os-odl_l3-nofeature-noha,fuel,33/36,92.0
+2017-04-29 01:45,os-nosdn-nofeature-ha,fuel,37/39,95.0
+2017-04-29 01:45,os-nosdn-lxd-noha,joid,11/24,46.0
+2017-04-29 01:45,os-odl_l2-nofeature-ha,joid,8/36,22.0
+2017-04-29 01:45,os-nosdn-lxd-ha,joid,18/24,75.0
+2017-04-29 01:45,os-nosdn-nofeature-ha,joid,29/33,88.0
+2017-04-29 01:45,os-nosdn-nofeature-noha,joid,22/33,67.0
+2017-04-30 01:45,os-nosdn-fdio-noha,apex,28/30,93.0
+2017-04-30 01:45,os-ovn-nofeature-noha,apex,6/33,18.0
+2017-04-30 01:45,os-odl_l2-fdio-noha,apex,19/36,53.0
+2017-04-30 01:45,os-odl_l3-fdio-noha,apex,24/30,80.0
+2017-04-30 01:45,os-odl_l3-nofeature-ha,apex,23/33,70.0
+2017-04-30 01:45,os-nosdn-kvm-ha,apex,20/33,61.0
+2017-04-30 01:45,os-nosdn-fdio-ha,apex,4/30,13.0
+2017-04-30 01:45,os-odl_l3-ovs-ha,apex,4/33,12.0
+2017-04-30 01:45,os-nosdn-ovs-ha,apex,4/33,12.0
+2017-04-30 01:45,os-odl_l2-fdio-ha,apex,30/36,83.0
+2017-04-30 01:45,os-nosdn-nofeature-ha,apex,20/33,61.0
+2017-04-30 01:45,os-odl_l3-nofeature-ha,compass,24/30,80.0
+2017-04-30 01:45,os-ocl-nofeature-ha,compass,3/30,10.0
+2017-04-30 01:45,os-onos-nofeature-ha,compass,28/33,85.0
+2017-04-30 01:45,os-odl_l2-nofeature-ha,compass,29/33,88.0
+2017-04-30 01:45,os-nosdn-openo-ha,compass,30/30,100.0
+2017-04-30 01:45,os-nosdn-nofeature-ha,compass,29/30,97.0
+2017-04-30 01:45,os-nosdn-kvm-noha,fuel,36/36,100.0
+2017-04-30 01:45,os-nosdn-kvm_ovs_dpdk_bar-ha,fuel,6/42,14.0
+2017-04-30 01:45,os-nosdn-ovs-ha,fuel,39/39,100.0
+2017-04-30 01:45,os-nosdn-kvm_ovs_dpdk_bar-noha,fuel,39/39,100.0
+2017-04-30 01:45,os-nosdn-ovs-noha,fuel,36/36,100.0
+2017-04-30 01:45,os-nosdn-kvm_ovs_dpdk-ha,fuel,6/39,15.0
+2017-04-30 01:45,os-odl_l2-sfc-noha,fuel,35/42,83.0
+2017-04-30 01:45,os-odl_l3-nofeature-ha,fuel,36/39,92.0
+2017-04-30 01:45,os-nosdn-kvm-ha,fuel,38/39,97.0
+2017-04-30 01:45,os-nosdn-nofeature-noha,fuel,36/36,100.0
+2017-04-30 01:45,os-odl_l2-nofeature-noha,fuel,35/39,90.0
+2017-04-30 01:45,os-odl_l2-bgpvpn-ha,fuel,37/42,88.0
+2017-04-30 01:45,os-odl_l2-sfc-ha,fuel,42/45,93.0
+2017-04-30 01:45,os-nosdn-kvm_ovs_dpdk-noha,fuel,36/36,100.0
+2017-04-30 01:45,os-odl_l2-bgpvpn-noha,fuel,41/42,98.0
+2017-04-30 01:45,os-odl_l2-nofeature-ha,fuel,41/42,98.0
+2017-04-30 01:45,os-odl_l3-nofeature-noha,fuel,35/36,97.0
+2017-04-30 01:45,os-nosdn-nofeature-ha,fuel,39/39,100.0
+2017-04-30 01:45,os-nosdn-lxd-noha,joid,12/24,50.0
+2017-04-30 01:45,os-nosdn-nofeature-noha,joid,33/33,100.0
+2017-04-30 01:45,os-nosdn-lxd-ha,joid,18/24,75.0
+2017-04-30 01:45,os-nosdn-nofeature-ha,joid,21/33,64.0
+2017-04-30 01:45,os-odl_l2-nofeature-ha,joid,8/36,22.0
+2017-05-01 01:45,os-nosdn-fdio-noha,apex,28/30,93.0
+2017-05-01 01:45,os-odl-gluon-noha,apex,9/36,25.0
+2017-05-01 01:45,os-ovn-nofeature-noha,apex,6/33,18.0
+2017-05-01 01:45,os-odl-bgpvpn-ha,apex,8/36,22.0
+2017-05-01 01:45,os-odl_l2-fdio-noha,apex,28/36,78.0
+2017-05-01 01:45,os-odl_l3-ovs-ha,apex,4/33,12.0
+2017-05-01 01:45,os-odl_l3-nofeature-ha,apex,23/33,70.0
+2017-05-01 01:45,os-nosdn-kvm-ha,apex,30/33,91.0
+2017-05-01 01:45,os-nosdn-fdio-ha,apex,6/30,20.0
+2017-05-01 01:45,os-odl_l3-fdio-noha,apex,23/30,77.0
+2017-05-01 01:45,os-nosdn-ovs-ha,apex,6/33,18.0
+2017-05-01 01:45,os-odl_l2-fdio-ha,apex,29/36,81.0
+2017-05-01 01:45,os-nosdn-nofeature-ha,apex,20/33,61.0
+2017-05-01 01:45,os-odl_l3-fdio-ha,apex,24/30,80.0
+2017-05-01 01:45,os-odl_l3-nofeature-ha,compass,26/30,87.0
+2017-05-01 01:45,os-ocl-nofeature-ha,compass,3/30,10.0
+2017-05-01 01:45,os-onos-nofeature-ha,compass,27/33,82.0
+2017-05-01 01:45,os-odl_l2-nofeature-ha,compass,28/33,85.0
+2017-05-01 01:45,os-nosdn-openo-ha,compass,30/30,100.0
+2017-05-01 01:45,os-nosdn-nofeature-ha,compass,29/30,97.0
+2017-05-01 01:45,os-nosdn-kvm-noha,fuel,36/36,100.0
+2017-05-01 01:45,os-nosdn-kvm_ovs_dpdk-noha,fuel,36/36,100.0
+2017-05-01 01:45,os-nosdn-ovs-ha,fuel,39/39,100.0
+2017-05-01 01:45,os-nosdn-ovs-noha,fuel,36/36,100.0
+2017-05-01 01:45,os-nosdn-kvm_ovs_dpdk-ha,fuel,6/39,15.0
+2017-05-01 01:45,os-odl_l2-sfc-noha,fuel,36/42,86.0
+2017-05-01 01:45,os-odl_l3-nofeature-ha,fuel,37/39,95.0
+2017-05-01 01:45,os-nosdn-kvm-ha,fuel,38/39,97.0
+2017-05-01 01:45,os-odl_l3-nofeature-noha,fuel,35/36,97.0
+2017-05-01 01:45,os-odl_l2-nofeature-noha,fuel,36/39,92.0
+2017-05-01 01:45,os-odl_l2-bgpvpn-ha,fuel,38/42,90.0
+2017-05-01 01:45,os-odl_l2-sfc-ha,fuel,44/45,98.0
+2017-05-01 01:45,os-nosdn-kvm_ovs_dpdk_bar-noha,fuel,39/39,100.0
+2017-05-01 01:45,os-odl_l2-bgpvpn-noha,fuel,41/42,98.0
+2017-05-01 01:45,os-nosdn-kvm_ovs_dpdk_bar-ha,fuel,6/42,14.0
+2017-05-01 01:45,os-odl_l2-nofeature-ha,fuel,41/42,98.0
+2017-05-01 01:45,os-nosdn-nofeature-noha,fuel,36/36,100.0
+2017-05-01 01:45,os-nosdn-nofeature-ha,fuel,39/39,100.0
+2017-05-01 01:45,os-nosdn-lxd-noha,joid,17/24,71.0
+2017-05-01 01:45,os-odl_l2-nofeature-ha,joid,9/36,25.0
+2017-05-01 01:45,os-nosdn-lxd-ha,joid,18/24,75.0
+2017-05-01 01:45,os-nosdn-nofeature-ha,joid,17/33,52.0
+2017-05-01 01:45,os-nosdn-nofeature-noha,joid,33/33,100.0
+2017-05-02 01:45,os-nosdn-fdio-noha,apex,28/30,93.0
+2017-05-02 01:45,os-odl-gluon-noha,apex,18/36,50.0
+2017-05-02 01:45,os-ovn-nofeature-noha,apex,9/33,27.0
+2017-05-02 01:45,os-odl-bgpvpn-ha,apex,16/36,44.0
+2017-05-02 01:45,os-odl_l2-fdio-noha,apex,28/36,78.0
+2017-05-02 01:45,os-odl_l3-ovs-ha,apex,4/33,12.0
+2017-05-02 01:45,os-odl_l3-nofeature-ha,apex,23/33,70.0
+2017-05-02 01:45,os-nosdn-kvm-ha,apex,30/33,91.0
+2017-05-02 01:45,os-nosdn-fdio-ha,apex,6/30,20.0
+2017-05-02 01:45,os-odl_l3-fdio-noha,apex,23/30,77.0
+2017-05-02 01:45,os-nosdn-ovs-ha,apex,6/33,18.0
+2017-05-02 01:45,os-odl_l2-fdio-ha,apex,29/36,81.0
+2017-05-02 01:45,os-nosdn-nofeature-ha,apex,30/33,91.0
+2017-05-02 01:45,os-odl_l3-fdio-ha,apex,24/30,80.0
+2017-05-02 01:45,os-odl_l3-nofeature-ha,compass,26/30,87.0
+2017-05-02 01:45,os-ocl-nofeature-ha,compass,3/30,10.0
+2017-05-02 01:45,os-onos-nofeature-ha,compass,27/33,82.0
+2017-05-02 01:45,os-odl_l2-nofeature-ha,compass,28/33,85.0
+2017-05-02 01:45,os-nosdn-openo-ha,compass,29/30,97.0
+2017-05-02 01:45,os-nosdn-nofeature-ha,compass,29/30,97.0
+2017-05-02 01:45,os-nosdn-kvm-noha,fuel,36/36,100.0
+2017-05-02 01:45,os-nosdn-kvm_ovs_dpdk_bar-ha,fuel,6/42,14.0
+2017-05-02 01:45,os-nosdn-kvm_ovs_dpdk-noha,fuel,36/36,100.0
+2017-05-02 01:45,os-nosdn-ovs-ha,fuel,39/39,100.0
+2017-05-02 01:45,os-nosdn-ovs-noha,fuel,36/36,100.0
+2017-05-02 01:45,os-nosdn-kvm_ovs_dpdk-ha,fuel,6/39,15.0
+2017-05-02 01:45,os-odl_l2-sfc-noha,fuel,38/42,90.0
+2017-05-02 01:45,os-odl_l3-nofeature-ha,fuel,37/39,95.0
+2017-05-02 01:45,os-nosdn-kvm-ha,fuel,39/39,100.0
+2017-05-02 01:45,os-odl_l3-nofeature-noha,fuel,36/36,100.0
+2017-05-02 01:45,os-odl_l2-nofeature-noha,fuel,38/39,97.0
+2017-05-02 01:45,os-odl_l2-bgpvpn-ha,fuel,38/42,90.0
+2017-05-02 01:45,os-odl_l2-sfc-ha,fuel,44/45,98.0
+2017-05-02 01:45,os-nosdn-kvm_ovs_dpdk_bar-noha,fuel,39/39,100.0
+2017-05-02 01:45,os-odl_l2-bgpvpn-noha,fuel,42/42,100.0
+2017-05-02 01:45,os-odl_l2-nofeature-ha,fuel,41/42,98.0
+2017-05-02 01:45,os-nosdn-nofeature-noha,fuel,36/36,100.0
+2017-05-02 01:45,os-nosdn-nofeature-ha,fuel,38/39,97.0
+2017-05-02 01:45,os-nosdn-lxd-noha,joid,18/24,75.0
+2017-05-02 01:45,os-nosdn-nofeature-noha,joid,33/33,100.0
+2017-05-02 01:45,os-nosdn-lxd-ha,joid,18/24,75.0
+2017-05-02 01:45,os-nosdn-nofeature-ha,joid,18/33,55.0
+2017-05-02 01:45,os-odl_l2-nofeature-ha,joid,9/36,25.0
+2017-05-03 01:45,os-nosdn-fdio-noha,apex,28/30,93.0
+2017-05-03 01:45,os-odl-gluon-noha,apex,18/36,50.0
+2017-05-03 01:45,os-ovn-nofeature-noha,apex,9/33,27.0
+2017-05-03 01:45,os-odl-bgpvpn-ha,apex,16/36,44.0
+2017-05-03 01:45,os-odl_l2-fdio-noha,apex,29/36,81.0
+2017-05-03 01:45,os-odl_l3-ovs-ha,apex,6/33,18.0
+2017-05-03 01:45,os-odl_l3-nofeature-ha,apex,23/33,70.0
+2017-05-03 01:45,os-nosdn-kvm-ha,apex,30/33,91.0
+2017-05-03 01:45,os-nosdn-fdio-ha,apex,6/30,20.0
+2017-05-03 01:45,os-odl_l3-fdio-noha,apex,23/30,77.0
+2017-05-03 01:45,os-nosdn-ovs-ha,apex,6/33,18.0
+2017-05-03 01:45,os-odl_l2-fdio-ha,apex,30/36,83.0
+2017-05-03 01:45,os-nosdn-nofeature-ha,apex,30/33,91.0
+2017-05-03 01:45,os-odl_l3-fdio-ha,apex,24/30,80.0
+2017-05-03 01:45,os-odl_l3-nofeature-ha,compass,25/30,83.0
+2017-05-03 01:45,os-ocl-nofeature-ha,compass,3/30,10.0
+2017-05-03 01:45,os-onos-nofeature-ha,compass,28/33,85.0
+2017-05-03 01:45,os-odl_l2-nofeature-ha,compass,28/33,85.0
+2017-05-03 01:45,os-nosdn-openo-ha,compass,29/30,97.0
+2017-05-03 01:45,os-nosdn-nofeature-ha,compass,30/30,100.0
+2017-05-03 01:45,os-nosdn-kvm_ovs_dpdk-noha,fuel,36/36,100.0
+2017-05-03 01:45,os-nosdn-kvm_ovs_dpdk_bar-ha,fuel,6/42,14.0
+2017-05-03 01:45,os-nosdn-kvm-noha,fuel,36/36,100.0
+2017-05-03 01:45,os-nosdn-ovs-noha,fuel,36/36,100.0
+2017-05-03 01:45,os-nosdn-kvm_ovs_dpdk-ha,fuel,6/39,15.0
+2017-05-03 01:45,os-odl_l2-sfc-noha,fuel,39/42,93.0
+2017-05-03 01:45,os-odl_l3-nofeature-ha,fuel,37/39,95.0
+2017-05-03 01:45,os-nosdn-kvm-ha,fuel,39/39,100.0
+2017-05-03 01:45,os-odl_l3-nofeature-noha,fuel,36/36,100.0
+2017-05-03 01:45,os-odl_l2-nofeature-noha,fuel,38/39,97.0
+2017-05-03 01:45,os-odl_l2-bgpvpn-ha,fuel,38/42,90.0
+2017-05-03 01:45,os-odl_l2-sfc-ha,fuel,45/45,100.0
+2017-05-03 01:45,os-nosdn-kvm_ovs_dpdk_bar-noha,fuel,39/39,100.0
+2017-05-03 01:45,os-odl_l2-bgpvpn-noha,fuel,42/42,100.0
+2017-05-03 01:45,os-odl_l2-nofeature-ha,fuel,41/42,98.0
+2017-05-03 01:45,os-nosdn-nofeature-noha,fuel,36/36,100.0
+2017-05-03 01:45,os-nosdn-nofeature-ha,fuel,37/39,95.0
+2017-05-03 01:45,os-nosdn-ovs-ha,fuel,39/39,100.0
+2017-05-03 01:45,os-nosdn-lxd-noha,joid,18/24,75.0
+2017-05-03 01:45,os-nosdn-nofeature-noha,joid,33/33,100.0
+2017-05-03 01:45,os-nosdn-lxd-ha,joid,18/24,75.0
+2017-05-03 01:45,os-nosdn-nofeature-ha,joid,22/33,67.0
+2017-05-03 01:45,os-odl_l2-nofeature-ha,joid,9/36,25.0
+2017-05-04 01:45,os-nosdn-fdio-noha,apex,28/30,93.0
+2017-05-04 01:45,os-odl-gluon-noha,apex,18/36,50.0
+2017-05-04 01:45,os-ovn-nofeature-noha,apex,9/33,27.0
+2017-05-04 01:45,os-odl-bgpvpn-ha,apex,16/36,44.0
+2017-05-04 01:45,os-odl_l2-fdio-noha,apex,29/36,81.0
+2017-05-04 01:45,os-odl_l3-ovs-ha,apex,6/33,18.0
+2017-05-04 01:45,os-odl_l3-nofeature-ha,apex,23/33,70.0
+2017-05-04 01:45,os-nosdn-kvm-ha,apex,30/33,91.0
+2017-05-04 01:45,os-nosdn-fdio-ha,apex,6/30,20.0
+2017-05-04 01:45,os-odl_l3-fdio-noha,apex,23/30,77.0
+2017-05-04 01:45,os-nosdn-ovs-ha,apex,6/33,18.0
+2017-05-04 01:45,os-odl_l2-fdio-ha,apex,30/36,83.0
+2017-05-04 01:45,os-nosdn-nofeature-ha,apex,30/33,91.0
+2017-05-04 01:45,os-odl_l3-fdio-ha,apex,24/30,80.0
+2017-05-04 01:45,os-odl_l3-nofeature-ha,compass,25/30,83.0
+2017-05-04 01:45,os-ocl-nofeature-ha,compass,3/30,10.0
+2017-05-04 01:45,os-onos-nofeature-ha,compass,28/33,85.0
+2017-05-04 01:45,os-odl_l2-nofeature-ha,compass,29/33,88.0
+2017-05-04 01:45,os-nosdn-openo-ha,compass,29/30,97.0
+2017-05-04 01:45,os-nosdn-nofeature-ha,compass,29/30,97.0
+2017-05-04 01:45,os-nosdn-kvm_ovs_dpdk-noha,fuel,36/36,100.0
+2017-05-04 01:45,os-nosdn-kvm_ovs_dpdk_bar-ha,fuel,6/42,14.0
+2017-05-04 01:45,os-nosdn-ovs-ha,fuel,39/39,100.0
+2017-05-04 01:45,os-nosdn-ovs-noha,fuel,36/36,100.0
+2017-05-04 01:45,os-nosdn-kvm_ovs_dpdk-ha,fuel,6/39,15.0
+2017-05-04 01:45,os-odl_l2-sfc-noha,fuel,39/42,93.0
+2017-05-04 01:45,os-odl_l3-nofeature-ha,fuel,38/39,97.0
+2017-05-04 01:45,os-nosdn-kvm-ha,fuel,39/39,100.0
+2017-05-04 01:45,os-odl_l3-nofeature-noha,fuel,36/36,100.0
+2017-05-04 01:45,os-odl_l2-nofeature-noha,fuel,37/39,95.0
+2017-05-04 01:45,os-odl_l2-bgpvpn-ha,fuel,40/42,95.0
+2017-05-04 01:45,os-odl_l2-sfc-ha,fuel,45/45,100.0
+2017-05-04 01:45,os-nosdn-kvm_ovs_dpdk_bar-noha,fuel,38/39,97.0
+2017-05-04 01:45,os-odl_l2-bgpvpn-noha,fuel,42/42,100.0
+2017-05-04 01:45,os-odl_l2-nofeature-ha,fuel,40/42,95.0
+2017-05-04 01:45,os-nosdn-nofeature-noha,fuel,36/36,100.0
+2017-05-04 01:45,os-nosdn-kvm-noha,fuel,36/36,100.0
+2017-05-04 01:45,os-nosdn-nofeature-ha,fuel,38/39,97.0
+2017-05-04 01:45,os-nosdn-lxd-noha,joid,18/24,75.0
+2017-05-04 01:45,os-nosdn-nofeature-noha,joid,33/33,100.0
+2017-05-04 01:45,os-nosdn-lxd-ha,joid,18/24,75.0
+2017-05-04 01:45,os-nosdn-nofeature-ha,joid,29/33,88.0
+2017-05-04 01:45,os-odl_l2-nofeature-ha,joid,9/36,25.0
+2017-05-05 01:45,os-nosdn-fdio-noha,apex,28/30,93.0
+2017-05-05 01:45,os-odl-gluon-noha,apex,18/36,50.0
+2017-05-05 01:45,os-ovn-nofeature-noha,apex,9/33,27.0
+2017-05-05 01:45,os-odl-bgpvpn-ha,apex,16/36,44.0
+2017-05-05 01:45,os-odl_l2-fdio-noha,apex,28/36,78.0
+2017-05-05 01:45,os-odl_l3-ovs-ha,apex,6/33,18.0
+2017-05-05 01:45,os-odl_l3-nofeature-ha,apex,23/33,70.0
+2017-05-05 01:45,os-nosdn-kvm-ha,apex,30/33,91.0
+2017-05-05 01:45,os-nosdn-fdio-ha,apex,6/30,20.0
+2017-05-05 01:45,os-odl_l3-fdio-noha,apex,23/30,77.0
+2017-05-05 01:45,os-nosdn-ovs-ha,apex,6/33,18.0
+2017-05-05 01:45,os-odl_l2-fdio-ha,apex,29/36,81.0
+2017-05-05 01:45,os-nosdn-nofeature-ha,apex,30/33,91.0
+2017-05-05 01:45,os-odl_l3-fdio-ha,apex,23/30,77.0
+2017-05-05 01:45,os-odl_l3-nofeature-ha,compass,25/30,83.0
+2017-05-05 01:45,os-ocl-nofeature-ha,compass,3/30,10.0
+2017-05-05 01:45,os-onos-nofeature-ha,compass,28/33,85.0
+2017-05-05 01:45,os-odl_l2-nofeature-ha,compass,28/33,85.0
+2017-05-05 01:45,os-nosdn-openo-ha,compass,29/30,97.0
+2017-05-05 01:45,os-nosdn-nofeature-ha,compass,29/30,97.0
+2017-05-05 01:45,os-nosdn-kvm_ovs_dpdk-noha,fuel,36/36,100.0
+2017-05-05 01:45,os-nosdn-kvm_ovs_dpdk_bar-ha,fuel,12/42,29.0
+2017-05-05 01:45,os-nosdn-kvm-noha,fuel,36/36,100.0
+2017-05-05 01:45,os-nosdn-ovs-noha,fuel,36/36,100.0
+2017-05-05 01:45,os-odl_l3-nofeature-noha,fuel,36/36,100.0
+2017-05-05 01:45,os-nosdn-kvm_ovs_dpdk-ha,fuel,6/39,15.0
+2017-05-05 01:45,os-odl_l2-sfc-noha,fuel,40/42,95.0
+2017-05-05 01:45,os-odl_l3-nofeature-ha,fuel,37/39,95.0
+2017-05-05 01:45,os-nosdn-kvm-ha,fuel,39/39,100.0
+2017-05-05 01:45,os-nosdn-nofeature-noha,fuel,36/36,100.0
+2017-05-05 01:45,os-odl_l2-nofeature-noha,fuel,38/39,97.0
+2017-05-05 01:45,os-odl_l2-bgpvpn-ha,fuel,39/42,93.0
+2017-05-05 01:45,os-odl_l2-sfc-ha,fuel,45/45,100.0
+2017-05-05 01:45,os-nosdn-kvm_ovs_dpdk_bar-noha,fuel,38/39,97.0
+2017-05-05 01:45,os-odl_l2-bgpvpn-noha,fuel,42/42,100.0
+2017-05-05 01:45,os-odl_l2-nofeature-ha,fuel,40/42,95.0
+2017-05-05 01:45,os-nosdn-nofeature-ha,fuel,39/39,100.0
+2017-05-05 01:45,os-nosdn-ovs-ha,fuel,39/39,100.0
+2017-05-05 01:45,os-nosdn-lxd-noha,joid,18/24,75.0
+2017-05-05 01:45,os-nosdn-nofeature-noha,joid,32/33,97.0
+2017-05-05 01:45,os-nosdn-lxd-ha,joid,17/24,71.0
+2017-05-05 01:45,os-nosdn-nofeature-ha,joid,32/33,97.0
+2017-05-05 01:45,os-odl_l2-nofeature-ha,joid,9/36,25.0
diff --git a/docs/results/danube/2.0/validated_scenario_history.txt b/docs/results/danube/2.0/validated_scenario_history.txt
new file mode 100644
index 000000000..15ec001e4
--- /dev/null
+++ b/docs/results/danube/2.0/validated_scenario_history.txt
@@ -0,0 +1,212 @@
+2017-03-19 02:03;compass;os-nosdn-nofeature-ha
+2017-03-20 02:04;compass;os-nosdn-nofeature-ha
+2017-03-21 02:03;compass;os-nosdn-nofeature-ha
+2017-03-22 02:01;apex;os-nosdn-nofeature-ha
+2017-03-23 02:14;joid;os-nosdn-nofeature-noha
+2017-03-24 02:09;fuel;os-nosdn-nofeature-noha
+2017-03-24 02:11;fuel;os-nosdn-ovs-ha
+2017-03-25 02:06;fuel;os-nosdn-ovs-noha
+2017-03-25 02:09;fuel;os-nosdn-nofeature-noha
+2017-03-25 02:11;fuel;os-nosdn-ovs-ha
+2017-03-26 02:06;fuel;os-nosdn-ovs-noha
+2017-03-26 02:09;fuel;os-nosdn-nofeature-noha
+2017-03-26 02:11;fuel;os-nosdn-ovs-ha
+2017-03-27 02:06;fuel;os-nosdn-ovs-noha
+2017-03-27 02:09;fuel;os-nosdn-nofeature-noha
+2017-03-27 02:11;fuel;os-nosdn-ovs-ha
+2017-03-28 02:04;compass;os-nosdn-openo-ha
+2017-03-28 02:04;compass;os-nosdn-nofeature-ha
+2017-03-28 02:04;fuel;os-nosdn-kvm_ovs_dpdk-noha
+2017-03-28 02:05;fuel;os-nosdn-kvm-noha
+2017-03-28 02:06;fuel;os-nosdn-ovs-noha
+2017-03-28 02:09;fuel;os-nosdn-nofeature-noha
+2017-03-28 13:40;compass;os-nosdn-openo-ha
+2017-03-28 13:41;fuel;os-nosdn-kvm_ovs_dpdk-noha
+2017-03-28 13:42;fuel;os-nosdn-kvm-noha
+2017-03-28 13:42;fuel;os-nosdn-ovs-noha
+2017-03-28 13:45;fuel;os-nosdn-nofeature-noha
+2017-03-28 13:48;fuel;os-odl_l2-nofeature-ha
+2017-03-28 14:15;compass;os-nosdn-openo-ha
+2017-03-28 14:16;fuel;os-nosdn-kvm_ovs_dpdk-noha
+2017-03-28 14:17;fuel;os-nosdn-kvm-noha
+2017-03-28 14:18;fuel;os-nosdn-ovs-noha
+2017-03-28 14:21;fuel;os-nosdn-nofeature-noha
+2017-03-28 14:23;fuel;os-odl_l2-nofeature-ha
+2017-03-28 16:33;apex;os-nosdn-nofeature-ha
+2017-03-28 16:36;fuel;os-nosdn-kvm_ovs_dpdk-noha
+2017-03-28 16:37;fuel;os-nosdn-kvm-noha
+2017-03-28 16:38;fuel;os-nosdn-ovs-noha
+2017-03-28 16:41;fuel;os-nosdn-nofeature-noha
+2017-03-28 16:43;fuel;os-odl_l2-nofeature-ha
+2017-03-29 02:02;apex;os-nosdn-nofeature-ha
+2017-03-29 02:05;fuel;os-nosdn-kvm_ovs_dpdk-noha
+2017-03-29 02:05;fuel;os-nosdn-kvm-noha
+2017-03-29 02:06;fuel;os-nosdn-ovs-noha
+2017-03-29 02:06;fuel;os-nosdn-nofeature-noha
+2017-03-29 02:11;fuel;os-odl_l2-nofeature-ha
+2017-03-30 02:02;apex;os-nosdn-nofeature-ha
+2017-03-30 02:05;fuel;os-nosdn-kvm_ovs_dpdk-noha
+2017-03-30 02:06;fuel;os-nosdn-kvm-noha
+2017-03-30 02:06;fuel;os-nosdn-ovs-noha
+2017-03-30 02:07;fuel;os-nosdn-nofeature-noha
+2017-03-30 02:11;fuel;os-odl_l2-nofeature-ha
+2017-03-31 02:04;apex;os-nosdn-nofeature-ha
+2017-03-31 02:07;fuel;os-nosdn-kvm_ovs_dpdk-noha
+2017-03-31 02:08;fuel;os-nosdn-kvm-noha
+2017-03-31 02:09;fuel;os-nosdn-ovs-noha
+2017-03-31 02:11;fuel;os-nosdn-nofeature-noha
+2017-03-31 02:13;fuel;os-nosdn-kvm_ovs_dpdk_bar-noha
+2017-03-31 02:14;fuel;os-odl_l2-nofeature-ha
+2017-04-01 02:04;apex;os-nosdn-nofeature-ha
+2017-04-01 02:07;compass;os-nosdn-nofeature-ha
+2017-04-01 02:07;fuel;os-nosdn-kvm_ovs_dpdk-noha
+2017-04-01 02:08;fuel;os-nosdn-kvm-noha
+2017-04-01 02:09;fuel;os-nosdn-ovs-noha
+2017-04-01 02:11;fuel;os-nosdn-nofeature-noha
+2017-04-01 02:13;fuel;os-nosdn-kvm_ovs_dpdk_bar-noha
+2017-04-01 02:15;fuel;os-nosdn-ovs-ha
+2017-04-02 02:04;apex;os-nosdn-nofeature-ha
+2017-04-02 02:07;compass;os-nosdn-nofeature-ha
+2017-04-02 02:07;fuel;os-nosdn-kvm-noha
+2017-04-02 02:08;fuel;os-nosdn-ovs-ha
+2017-04-02 02:09;fuel;os-nosdn-kvm_ovs_dpdk_bar-noha
+2017-04-02 02:09;fuel;os-nosdn-ovs-noha
+2017-04-02 02:11;fuel;os-nosdn-nofeature-noha
+2017-04-02 02:13;fuel;os-nosdn-kvm_ovs_dpdk-noha
+2017-04-03 02:04;apex;os-nosdn-kvm-ha
+2017-04-03 02:04;apex;os-nosdn-nofeature-ha
+2017-04-03 02:07;compass;os-nosdn-nofeature-ha
+2017-04-03 02:07;fuel;os-nosdn-kvm-noha
+2017-04-03 02:08;fuel;os-nosdn-ovs-ha
+2017-04-03 02:09;fuel;os-nosdn-kvm_ovs_dpdk_bar-noha
+2017-04-03 02:09;fuel;os-nosdn-ovs-noha
+2017-04-03 02:12;fuel;os-nosdn-nofeature-noha
+2017-04-03 02:14;fuel;os-nosdn-kvm_ovs_dpdk-noha
+2017-04-04 02:02;apex;os-nosdn-kvm-ha
+2017-04-04 02:05;apex;os-nosdn-nofeature-ha
+2017-04-04 02:07;compass;os-nosdn-nofeature-ha
+2017-04-04 02:09;fuel;os-nosdn-ovs-ha
+2017-04-04 02:09;fuel;os-nosdn-kvm_ovs_dpdk_bar-noha
+2017-04-04 02:10;fuel;os-nosdn-ovs-noha
+2017-04-04 02:14;fuel;os-nosdn-kvm_ovs_dpdk-noha
+2017-04-05 02:00;apex;os-nosdn-kvm-ha
+2017-04-05 02:03;apex;os-nosdn-nofeature-ha
+2017-04-05 02:06;compass;os-nosdn-nofeature-ha
+2017-04-05 02:07;fuel;os-nosdn-ovs-ha
+2017-04-05 02:08;fuel;os-nosdn-kvm_ovs_dpdk_bar-noha
+2017-04-05 02:08;fuel;os-nosdn-ovs-noha
+2017-04-05 02:13;fuel;os-nosdn-kvm_ovs_dpdk-noha
+2017-04-06 02:07;compass;os-nosdn-nofeature-ha
+2017-04-06 02:08;fuel;os-nosdn-ovs-ha
+2017-04-06 02:09;fuel;os-nosdn-kvm_ovs_dpdk_bar-noha
+2017-04-06 02:09;fuel;os-nosdn-ovs-noha
+2017-04-06 02:14;fuel;os-nosdn-kvm_ovs_dpdk-noha
+2017-04-07 02:08;fuel;os-nosdn-ovs-ha
+2017-04-07 02:09;fuel;os-nosdn-kvm_ovs_dpdk_bar-noha
+2017-04-07 02:09;fuel;os-nosdn-ovs-noha
+2017-04-07 02:14;fuel;os-nosdn-kvm_ovs_dpdk-noha
+2017-04-08 02:08;fuel;os-nosdn-ovs-ha
+2017-04-08 02:09;fuel;os-nosdn-kvm_ovs_dpdk_bar-noha
+2017-04-08 02:09;fuel;os-nosdn-ovs-noha
+2017-04-08 02:14;fuel;os-nosdn-kvm_ovs_dpdk-noha
+2017-04-09 02:07;fuel;os-nosdn-kvm-noha
+2017-04-09 02:08;fuel;os-nosdn-ovs-ha
+2017-04-09 02:08;fuel;os-nosdn-kvm_ovs_dpdk_bar-noha
+2017-04-09 02:09;fuel;os-nosdn-ovs-noha
+2017-04-09 02:14;fuel;os-nosdn-kvm_ovs_dpdk-noha
+2017-04-10 02:07;fuel;os-nosdn-kvm-noha
+2017-04-10 02:08;fuel;os-nosdn-ovs-ha
+2017-04-10 02:08;fuel;os-nosdn-kvm_ovs_dpdk_bar-noha
+2017-04-10 02:09;fuel;os-nosdn-ovs-noha
+2017-04-10 02:11;fuel;os-nosdn-nofeature-noha
+2017-04-10 02:13;fuel;os-nosdn-kvm_ovs_dpdk-noha
+2017-04-11 02:06;compass;os-nosdn-nofeature-ha
+2017-04-11 02:06;fuel;os-nosdn-kvm-noha
+2017-04-11 02:07;fuel;os-nosdn-ovs-ha
+2017-04-11 02:08;fuel;os-nosdn-kvm_ovs_dpdk_bar-noha
+2017-04-11 02:08;fuel;os-nosdn-ovs-noha
+2017-04-11 02:11;fuel;os-nosdn-nofeature-noha
+2017-04-11 02:13;fuel;os-nosdn-kvm_ovs_dpdk-noha
+2017-04-11 02:15;fuel;os-nosdn-nofeature-ha
+2017-04-12 02:07;fuel;os-nosdn-ovs-ha
+2017-04-12 02:07;fuel;os-nosdn-kvm_ovs_dpdk_bar-noha
+2017-04-12 02:08;fuel;os-nosdn-ovs-noha
+2017-04-12 02:11;fuel;os-nosdn-nofeature-noha
+2017-04-12 02:13;fuel;os-nosdn-kvm_ovs_dpdk-noha
+2017-04-12 02:14;fuel;os-nosdn-nofeature-ha
+2017-04-28 20:46;compass;os-nosdn-openo-ha
+2017-04-28 20:48;fuel;os-nosdn-kvm-noha
+2017-04-28 20:49;fuel;os-nosdn-kvm_ovs_dpdk-noha
+2017-04-28 20:49;fuel;os-nosdn-ovs-noha
+2017-04-28 20:52;fuel;os-nosdn-kvm-ha
+2017-04-28 20:54;fuel;os-nosdn-kvm_ovs_dpdk_bar-noha
+2017-04-28 20:55;fuel;os-nosdn-ovs-ha
+2017-04-28 20:56;fuel;os-nosdn-nofeature-noha
+2017-04-29 02:07;compass;os-nosdn-openo-ha
+2017-04-29 02:08;fuel;os-nosdn-kvm-noha
+2017-04-29 02:09;fuel;os-nosdn-ovs-ha
+2017-04-29 02:10;fuel;os-nosdn-kvm_ovs_dpdk_bar-noha
+2017-04-29 02:10;fuel;os-nosdn-ovs-noha
+2017-04-29 02:12;fuel;os-nosdn-kvm-ha
+2017-04-29 02:13;fuel;os-nosdn-nofeature-noha
+2017-04-29 02:15;fuel;os-nosdn-kvm_ovs_dpdk-noha
+2017-04-30 02:07;compass;os-nosdn-openo-ha
+2017-04-30 02:08;fuel;os-nosdn-kvm-noha
+2017-04-30 02:09;fuel;os-nosdn-ovs-ha
+2017-04-30 02:10;fuel;os-nosdn-kvm_ovs_dpdk_bar-noha
+2017-04-30 02:10;fuel;os-nosdn-ovs-noha
+2017-04-30 02:13;fuel;os-nosdn-nofeature-noha
+2017-04-30 02:15;fuel;os-nosdn-kvm_ovs_dpdk-noha
+2017-04-30 02:17;fuel;os-nosdn-nofeature-ha
+2017-04-30 02:18;joid;os-nosdn-nofeature-noha
+2017-05-01 02:09;compass;os-nosdn-openo-ha
+2017-05-01 02:10;fuel;os-nosdn-kvm-noha
+2017-05-01 02:10;fuel;os-nosdn-kvm_ovs_dpdk-noha
+2017-05-01 02:11;fuel;os-nosdn-ovs-ha
+2017-05-01 02:11;fuel;os-nosdn-ovs-noha
+2017-05-01 02:16;fuel;os-nosdn-kvm_ovs_dpdk_bar-noha
+2017-05-01 02:18;fuel;os-nosdn-nofeature-noha
+2017-05-01 02:18;fuel;os-nosdn-nofeature-ha
+2017-05-01 02:21;joid;os-nosdn-nofeature-noha
+2017-05-02 02:10;fuel;os-nosdn-kvm-noha
+2017-05-02 02:11;fuel;os-nosdn-kvm_ovs_dpdk-noha
+2017-05-02 02:11;fuel;os-nosdn-ovs-ha
+2017-05-02 02:12;fuel;os-nosdn-ovs-noha
+2017-05-02 02:14;fuel;os-nosdn-kvm-ha
+2017-05-02 02:14;fuel;os-odl_l3-nofeature-noha
+2017-05-02 02:16;fuel;os-nosdn-kvm_ovs_dpdk_bar-noha
+2017-05-02 02:17;fuel;os-odl_l2-bgpvpn-noha
+2017-05-02 02:18;fuel;os-nosdn-nofeature-noha
+2017-05-02 02:19;joid;os-nosdn-nofeature-noha
+2017-05-03 02:09;compass;os-nosdn-nofeature-ha
+2017-05-03 02:10;fuel;os-nosdn-kvm_ovs_dpdk-noha
+2017-05-03 02:11;fuel;os-nosdn-kvm-noha
+2017-05-03 02:11;fuel;os-nosdn-ovs-noha
+2017-05-03 02:13;fuel;os-nosdn-kvm-ha
+2017-05-03 02:14;fuel;os-odl_l3-nofeature-noha
+2017-05-03 02:15;fuel;os-odl_l2-sfc-ha
+2017-05-03 02:16;fuel;os-nosdn-kvm_ovs_dpdk_bar-noha
+2017-05-03 02:16;fuel;os-odl_l2-bgpvpn-noha
+2017-05-03 02:17;fuel;os-nosdn-nofeature-noha
+2017-05-03 02:18;fuel;os-nosdn-ovs-ha
+2017-05-03 02:19;joid;os-nosdn-nofeature-noha
+2017-05-04 02:10;fuel;os-nosdn-kvm_ovs_dpdk-noha
+2017-05-04 02:11;fuel;os-nosdn-ovs-ha
+2017-05-04 02:11;fuel;os-nosdn-ovs-noha
+2017-05-04 02:13;fuel;os-nosdn-kvm-ha
+2017-05-04 02:14;fuel;os-odl_l3-nofeature-noha
+2017-05-04 02:15;fuel;os-odl_l2-sfc-ha
+2017-05-04 02:16;fuel;os-odl_l2-bgpvpn-noha
+2017-05-04 02:17;fuel;os-nosdn-nofeature-noha
+2017-05-04 02:18;fuel;os-nosdn-kvm-noha
+2017-05-04 02:19;joid;os-nosdn-nofeature-noha
+2017-05-05 02:10;fuel;os-nosdn-kvm_ovs_dpdk-noha
+2017-05-05 02:11;fuel;os-nosdn-kvm-noha
+2017-05-05 02:11;fuel;os-nosdn-ovs-noha
+2017-05-05 02:12;fuel;os-odl_l3-nofeature-noha
+2017-05-05 02:14;fuel;os-nosdn-kvm-ha
+2017-05-05 02:14;fuel;os-nosdn-nofeature-noha
+2017-05-05 02:16;fuel;os-odl_l2-sfc-ha
+2017-05-05 02:17;fuel;os-odl_l2-bgpvpn-noha
+2017-05-05 02:18;fuel;os-nosdn-nofeature-ha
+2017-05-05 02:18;fuel;os-nosdn-ovs-ha
diff --git a/docs/testing/user/configguide/configguide.rst b/docs/testing/user/configguide/configguide.rst
index e3485be40..9a1749789 100644
--- a/docs/testing/user/configguide/configguide.rst
+++ b/docs/testing/user/configguide/configguide.rst
@@ -336,6 +336,7 @@ should now be in place::
|-- parser
|-- promise
|-- rally
+ |-- refstack-client
|-- releng
|-- sdnvpn
|-- securityscanning
diff --git a/docs/testing/user/userguide/index.rst b/docs/testing/user/userguide/index.rst
index e050cf14b..c1faecdaa 100644
--- a/docs/testing/user/userguide/index.rst
+++ b/docs/testing/user/userguide/index.rst
@@ -247,13 +247,125 @@ The Rally testcases are distributed accross two Tiers:
NOTE: Test case 'rally_sanity' executes a limited number of Rally smoke test
cases. Test case 'rally_full' executes the full defined set of Rally tests.
+
+Refstack-client to run Defcore testcases
+-----------------------------------------
+
+Refstack-client `[8]`_ is a command line utility that allows you to
+execute Tempest test runs based on configurations you specify.
+It is the official tool to run Defcore `[9]`_ testcases,
+which focuses on testing interoperability between OpenStack clouds.
+
+Refstack-client is integrated in Functest, consumed by Dovetail, which
+intends to define and provide a set of OPNFV related validation criteria
+that will provide input for the evaluation of the use of OPNFV trademarks.
+This progress is under the guideline of Compliance Verification Program(CVP).
+
+Defcore testcases
+^^^^^^^^^^^^^^^^^^
+
+*Danube Release*
+
+Set of DefCore tempest test cases not flagged and required.
+According to `[10]`_, some tests are still flagged due to outstanding bugs
+in the Tempest library, particularly tests that require SSH. Refstack developers
+are working on correcting these bugs upstream. Please note that although some tests
+are flagged because of bugs, there is still an expectation that the capabilities
+covered by the tests are available. It only contains Openstack core compute
+(no object storage). The approved guidelines (2016.08) are valid for Kilo,
+Liberty, Mitaka and Newton releases of OpenStack.
+The list can be generated using the Rest API from RefStack project:
+https://refstack.openstack.org/api/v1/guidelines/2016.08/tests?target=compute&type=required&alias=true&flag=false
+
+Running methods
+^^^^^^^^^^^^^^^
+
+Two running methods are provided after refstack-client integrated into
+Functest, Functest command line and manually, respectively.
+
+By default, for Defcore test cases run by Functest command line,
+are run followed with automatically generated
+configuration file, i.e., refstack_tempest.conf. In some circumstances,
+the automatic configuration file may not quite satisfied with the SUT,
+Functest also inherits the refstack-client command line and provides a way
+for users to set its configuration file according to its own SUT manually.
+
+*command line*
+
+Inside the Functest container, first to prepare Functest environment:
+
+::
+
+ cd /home/opnfv/repos/functest
+ pip install -e .
+ functest env prepare
+
+then to run default defcore testcases by using refstack-client:
+
+::
+
+ functest testcase run refstack_defcore
+
+In OPNFV Continuous Integration(CI) system, the command line method is used.
+
+*manually*
+
+Inside the Functest container, first to prepare the refstack virtualenv:
+
+::
+
+ cd /home/opnfv/repos/refstack-client
+ source .venv/bin/activate
+
+then prepare the tempest configuration file and the testcases want to run with the SUT,
+run the testcases with:
+
+::
+
+ ./refstack-client test -c <Path of the tempest configuration file to use> -v --test-list <Path or URL of test list>
+
+using help for more information:
+
+::
+
+ ./refstack-client --help
+ ./refstack-client test --help
+
+Reference tempest configuration
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+*command line method*
+
+When command line method is used, the default tempest configuration file
+is generated by Rally.
+
+*manually*
+
+When running manually is used, recommended way to generate tempest configuration
+file is:
+
+::
+
+ cd /home/opnfv/repos/functest/functest/opnfv_tests/openstack/refstack_client
+ python tempest_conf.py
+
+a file called tempest.conf is stored in the current path by default, users can do
+some adjustment according to the SUT:
+
+::
+
+ vim refstack_tempest.conf
+
+a reference article can be used `[15]`_.
+
+
snaps_smoke
------------
This test case contains tests that setup and destroy environments with VMs with
and without Floating IPs with a newly created user and project. Set the config
value snaps.use_floating_ips (True|False) to toggle this functionality. When
-the config value of snaps.use_keystone is True, functest must have access
+the config value of snaps.use_keystone is True, Functest must have access
the cloud's private network.
This suite consists in 38 tests (test duration < 10 minutes)
@@ -362,7 +474,7 @@ The test cases are described as follows:
Features
--------
-In Danube, functest supports the integration of:
+In Danube, Functest supports the integration of:
* barometer
* bgpvpn
@@ -520,10 +632,14 @@ References
.. _`[5]`: https://github.com/Orange-OpenSource/opnfv-cloudify-clearwater/blob/master/openstack-blueprint.yaml
.. _`[6]`: https://scap.nist.gov/
.. _`[7]`: https://github.com/OpenSCAP/openscap
+.. _`[8]`: https://github.com/openstack/refstack-client
+.. _`[9]`: https://github.com/openstack/defcore
+.. _`[10]`: https://github.com/openstack/interop/blob/master/2016.08/procedure.rst
.. _`[11]`: http://robotframework.org/
.. _`[12]`: http://artifacts.opnfv.org/parser/colorado/docs/userguide/index.html
.. _`[13]`: https://wiki.opnfv.org/display/PROJ/SNAPS-OO
.. _`[14]`: https://github.com/oolorg/opnfv-functest-vrouter
+.. _`[15]`: https://aptira.com/testing-openstack-tempest-part-1/
`OPNFV main site`_
diff --git a/functest/ci/check_os.sh b/functest/ci/check_os.sh
index 83f9f476d..ce0bc20c6 100755
--- a/functest/ci/check_os.sh
+++ b/functest/ci/check_os.sh
@@ -86,30 +86,6 @@ if [ $RETVAL -ne 0 ]; then
fi
echo " ...OK"
-adminURL=$(openstack catalog show identity |awk '/admin/ {print $4}')
-if [ -z ${adminURL} ]; then
- echo "ERROR: Cannot determine the admin URL."
- openstack catalog show identity
- exit 1
-fi
-adminIP=$(echo $adminURL|sed 's/^.*http.*\:\/\///'|sed 's/.[^:]*$//')
-adminPort=$(echo $adminURL|grep -Po '(?<=:)\d+')
-https_enabled=$(echo $adminURL | grep 'https')
-if [[ -n $https_enabled ]]; then
- echo ">>Verifying SSL connectivity to the admin endpoint $adminIP:$adminPort..."
- verify_SSL_connectivity $adminIP $adminPort
-else
- echo ">>Verifying connectivity to the admin endpoint $adminIP:$adminPort..."
- verify_connectivity $adminIP $adminPort
-fi
-RETVAL=$?
-if [ $RETVAL -ne 0 ]; then
- echo "ERROR: Cannot talk to the admin endpoint $adminIP:$adminPort ."
- echo "$adminURL"
- exit 1
-fi
-echo " ...OK"
-
echo "Checking Required OpenStack services:"
for service in $MANDATORY_SERVICES; do
diff --git a/functest/ci/config_functest.yaml b/functest/ci/config_functest.yaml
index 96dd62129..9b7960718 100644
--- a/functest/ci/config_functest.yaml
+++ b/functest/ci/config_functest.yaml
@@ -34,10 +34,11 @@ general:
functest: /home/opnfv/functest
functest_test: /home/opnfv/repos/functest/functest/opnfv_tests
results: /home/opnfv/functest/results
- functest_logging_cfg: /home/opnfv/repos/functest/functest/ci/logging.json
+ functest_logging_cfg: /home/opnfv/repos/functest/functest/ci/logging.ini
functest_conf: /home/opnfv/functest/conf
functest_data: /home/opnfv/functest/data
ims_data: /home/opnfv/functest/data/ims/
+ functest_images: /home/opnfv/functest/images
rally_inst: /home/opnfv/.rally
repo_kingbird: /home/opnfv/repos/kingbird
refstack_client: /home/opnfv/repos/refstack-client
@@ -49,6 +50,8 @@ general:
image_name: Cirros-0.3.5
image_name_alt: Cirros-0.3.5-1
image_file_name: cirros-0.3.5-x86_64-disk.img
+ image_url: http://download.cirros-cloud.net/0.3.5/cirros-0.3.5-x86_64-disk.img
+ image_user: cirros
image_disk_format: qcow2
image_username: cirros
image_password: cubswin:)
@@ -71,14 +74,23 @@ general:
functest:
testcases_yaml: /home/opnfv/repos/functest/functest/ci/testcases.yaml
-healthcheck:
- disk_image: /home/opnfv/functest/data/cirros-0.3.5-x86_64-disk.img
- disk_format: qcow2
- wait_time: 60
-
snaps:
use_keystone: True
- use_floating_ips: False
+ use_floating_ips: True
+# images:
+# cirros:
+# disk_url: http://download.cirros-cloud.net/0.3.5/cirros-0.3.5-x86_64-disk.img
+ # ARM
+# disk_url: http://download.cirros-cloud.net/daily/20161201/cirros-d161201-aarch64-disk.img
+# kernel_url: http://download.cirros-cloud.net/daily/20161201/cirros-d161201-aarch64-kernel
+# ramdisk_url: http://download.cirros-cloud.net/daily/20161201/cirros-d161201-aarch64-initramfs
+# extra_properties:
+# os_command_line: root=/dev/vdb1 rw rootwait console=tty0 console=ttyS0 console=ttyAMA0
+# hw_video_model: vga
+# ubuntu:
+# disk_url: http://uec-images.ubuntu.com/releases/trusty/14.04/ubuntu-14.04-server-cloudimg-amd64-disk1.img
+# centos:
+# disk_url: http://cloud.centos.org/centos/7/images/CentOS-7-x86_64-GenericCloud.qcow2
vping:
ping_timeout: 200
@@ -92,6 +104,14 @@ vping:
router_name: vping-router
sg_name: vPing-sg
sg_desc: Security group for vPing test case
+ keypair_name: vPing-keypair
+ keypair_priv_file: /tmp/vPing-keypair
+ keypair_pub_file: /tmp/vPing-keypair.pub
+ vm_boot_timeout: 180
+ vm_delete_timeout: 100
+ vm_ssh_connect_timeout: 60
+ cleanup_objects: True
+ unique_names: True
onos_sfc:
image_base_url: http://artifacts.opnfv.org/sfc/demo
@@ -210,3 +230,8 @@ results:
# you can also set a file (e.g. /home/opnfv/functest/results/dump.txt) to dump results
# test_db_url: file:///home/opnfv/functest/results/dump.txt
test_db_url: http://testresults.opnfv.org/test/api/v1/results
+
+energy_recorder:
+ api_url: http://161.105.253.100:8888/resources
+ api_user: ""
+ api_password: ""
diff --git a/functest/ci/download_images.sh b/functest/ci/download_images.sh
new file mode 100644
index 000000000..f3fdef2e3
--- /dev/null
+++ b/functest/ci/download_images.sh
@@ -0,0 +1,31 @@
+#!/bin/bash
+
+CIRROS_REPO_URL=http://download.cirros-cloud.net
+CIRROS_AARCH64_TAG=161201
+CIRROS_X86_64_TAG=0.3.5
+
+RED='\033[1;31m'
+NC='\033[0m' # No Color
+
+function usage(){
+ echo -e "${RED}USAGE: $script <destination_folder>${NC}"
+ exit 0
+}
+
+script=`basename "$0"`
+IMAGES_FOLDER_DIR=$1
+
+if [[ -z $IMAGES_FOLDER_DIR ]]; then usage; fi;
+
+set -ex
+mkdir -p ${IMAGES_FOLDER_DIR}
+
+wget -nc ${CIRROS_REPO_URL}/${CIRROS_X86_64_TAG}/cirros-${CIRROS_X86_64_TAG}-x86_64-disk.img -P ${IMAGES_FOLDER_DIR}
+wget -nc ${CIRROS_REPO_URL}/${CIRROS_X86_64_TAG}/cirros-${CIRROS_X86_64_TAG}-x86_64-lxc.tar.gz -P ${IMAGES_FOLDER_DIR}
+wget -nc http://artifacts.opnfv.org/sdnvpn/ubuntu-16.04-server-cloudimg-amd64-disk1.img -P ${IMAGES_FOLDER_DIR}
+
+# Add 3rd-party images for aarch64, since Functest can be run on an x86 machine to test an aarch64 POD
+wget -nc ${CIRROS_REPO_URL}/daily/20${CIRROS_AARCH64_TAG}/cirros-d${CIRROS_AARCH64_TAG}-aarch64-disk.img -P ${IMAGES_FOLDER_DIR}
+wget -nc ${CIRROS_REPO_URL}/daily/20${CIRROS_AARCH64_TAG}/cirros-d${CIRROS_AARCH64_TAG}-aarch64-initramfs -P ${IMAGES_FOLDER_DIR}
+wget -nc ${CIRROS_REPO_URL}/daily/20${CIRROS_AARCH64_TAG}/cirros-d${CIRROS_AARCH64_TAG}-aarch64-kernel -P ${IMAGES_FOLDER_DIR}
+set +ex \ No newline at end of file
diff --git a/functest/ci/generate_report.py b/functest/ci/generate_report.py
deleted file mode 100755
index 3872a07ed..000000000
--- a/functest/ci/generate_report.py
+++ /dev/null
@@ -1,153 +0,0 @@
-#!/usr/bin/env python
-#
-# 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 json
-import re
-import urllib2
-
-import functest.utils.functest_logger as ft_logger
-import functest.utils.functest_utils as ft_utils
-from functest.utils.constants import CONST
-
-COL_1_LEN = 25
-COL_2_LEN = 15
-COL_3_LEN = 12
-COL_4_LEN = 15
-COL_5_LEN = 75
-
-# If we run from CI (Jenkins) we will push the results to the DB
-# and then we can print the url to the specific test result
-
-
-logger = ft_logger.Logger("generate_report").getLogger()
-
-
-def init(tiers_to_run=[]):
- test_cases_arr = []
- for tier in tiers_to_run:
- for test in tier.get_tests():
- test_cases_arr.append({'test_name': test.get_name(),
- 'tier_name': tier.get_name(),
- 'result': 'Not executed',
- 'duration': '0',
- 'url': ''})
- return test_cases_arr
-
-
-def get_results_from_db():
- url = "%s/results?build_tag=%s" % (ft_utils.get_db_url(),
- CONST.BUILD_TAG)
- logger.debug("Query to rest api: %s" % url)
- try:
- data = json.load(urllib2.urlopen(url))
- return data['results']
- except:
- logger.error("Cannot read content from the url: %s" % url)
- return None
-
-
-def get_data(test, results):
- test_result = test['result']
- url = ''
- for test_db in results:
- if test['test_name'] in test_db['case_name']:
- id = test_db['_id']
- url = ft_utils.get_db_url() + '/results/' + id
- test_result = test_db['criteria']
-
- return {"url": url, "result": test_result}
-
-
-def print_line(w1, w2='', w3='', w4='', w5=''):
- str = ('| ' + w1.ljust(COL_1_LEN - 1) +
- '| ' + w2.ljust(COL_2_LEN - 1) +
- '| ' + w3.ljust(COL_3_LEN - 1) +
- '| ' + w4.ljust(COL_4_LEN - 1))
- if CONST.IS_CI_RUN:
- str += ('| ' + w5.ljust(COL_5_LEN - 1))
- str += '|\n'
- return str
-
-
-def print_line_no_columns(str):
- TOTAL_LEN = COL_1_LEN + COL_2_LEN + COL_3_LEN + COL_4_LEN + 2
- if CONST.IS_CI_RUN:
- TOTAL_LEN += COL_5_LEN + 1
- return ('| ' + str.ljust(TOTAL_LEN) + "|\n")
-
-
-def print_separator(char="=", delimiter="+"):
- str = ("+" + char * COL_1_LEN +
- delimiter + char * COL_2_LEN +
- delimiter + char * COL_3_LEN +
- delimiter + char * COL_4_LEN)
- if CONST.IS_CI_RUN:
- str += (delimiter + char * COL_5_LEN)
- str += '+\n'
- return str
-
-
-def main(args=[]):
- executed_test_cases = args
-
- if CONST.IS_CI_RUN:
- results = get_results_from_db()
- if results is not None:
- for test in executed_test_cases:
- data = get_data(test, results)
- test.update({"url": data['url'],
- "result": data['result']})
-
- TOTAL_LEN = COL_1_LEN + COL_2_LEN + COL_3_LEN + COL_4_LEN
- if CONST.IS_CI_RUN:
- TOTAL_LEN += COL_5_LEN
- MID = TOTAL_LEN / 2
-
- if CONST.BUILD_TAG is not None:
- if re.search("daily", CONST.BUILD_TAG) is not None:
- CONST.CI_LOOP = "daily"
- else:
- CONST.CI_LOOP = "weekly"
-
- str = ''
- str += print_separator('=', delimiter="=")
- str += print_line_no_columns(' ' * (MID - 8) + 'FUNCTEST REPORT')
- str += print_separator('=', delimiter="=")
- str += print_line_no_columns(' ')
- str += print_line_no_columns(" Deployment description:")
- str += print_line_no_columns(" INSTALLER: %s"
- % CONST.INSTALLER_TYPE)
- if CONST.DEPLOY_SCENARIO is not None:
- str += print_line_no_columns(" SCENARIO: %s"
- % CONST.DEPLOY_SCENARIO)
- if CONST.BUILD_TAG is not None:
- str += print_line_no_columns(" BUILD TAG: %s"
- % CONST.BUILD_TAG)
- if CONST.CI_LOOP is not None:
- str += print_line_no_columns(" CI LOOP: %s"
- % CONST.CI_LOOP)
- str += print_line_no_columns(' ')
- str += print_separator('=')
- if CONST.IS_CI_RUN:
- str += print_line('TEST CASE', 'TIER', 'DURATION', 'RESULT', 'URL')
- else:
- str += print_line('TEST CASE', 'TIER', 'DURATION', 'RESULT')
- str += print_separator('=')
- for test in executed_test_cases:
- str += print_line(test['test_name'],
- test['tier_name'],
- test['duration'],
- test['result'],
- test['url'])
- str += print_separator('-')
-
- logger.info("\n\n\n%s" % str)
-
-
-if __name__ == '__main__':
- import sys
- main(sys.argv[1:])
diff --git a/functest/ci/logging.ini b/functest/ci/logging.ini
new file mode 100644
index 000000000..210c8f5f4
--- /dev/null
+++ b/functest/ci/logging.ini
@@ -0,0 +1,75 @@
+[loggers]
+keys=root,functest,ci,cli,core,energy,opnfv_tests,utils
+
+[handlers]
+keys=console,wconsole,file,null
+
+[formatters]
+keys=standard
+
+[logger_root]
+level=NOTSET
+handlers=null
+
+[logger_functest]
+level=NOTSET
+handlers=file
+qualname=functest
+
+[logger_ci]
+level=NOTSET
+handlers=console
+qualname=functest.ci
+
+[logger_cli]
+level=NOTSET
+handlers=wconsole
+qualname=functest.cli
+
+[logger_core]
+level=NOTSET
+handlers=console
+qualname=functest.core
+
+[logger_energy]
+level=NOTSET
+handlers=wconsole
+qualname=functest.energy
+
+[logger_opnfv_tests]
+level=NOTSET
+handlers=wconsole
+qualname=functest.opnfv_tests
+
+[logger_utils]
+level=NOTSET
+handlers=wconsole
+qualname=functest.utils
+
+[handler_null]
+class=NullHandler
+level=NOTSET
+formatter=standard
+args=()
+
+[handler_console]
+class=StreamHandler
+level=INFO
+formatter=standard
+args=(sys.stdout,)
+
+[handler_wconsole]
+class=StreamHandler
+level=WARN
+formatter=standard
+args=(sys.stdout,)
+
+[handler_file]
+class=FileHandler
+level=DEBUG
+formatter=standard
+args=("/home/opnfv/functest/results/functest.log",)
+
+[formatter_standard]
+format=%(asctime)s - %(name)s - %(levelname)s - %(message)s
+datefmt=
diff --git a/functest/ci/logging.json b/functest/ci/logging.json
deleted file mode 100644
index 2a2399d38..000000000
--- a/functest/ci/logging.json
+++ /dev/null
@@ -1,29 +0,0 @@
-{
- "version": 1,
- "disable_existing_loggers": false,
- "formatters": {
- "standard": {
- "format": "%(asctime)s - %(name)s - %(levelname)s - %(message)s"
- }
- },
- "handlers": {
- "console": {
- "level": "INFO",
- "class": "logging.StreamHandler",
- "formatter": "standard"
- },
- "file": {
- "level": "DEBUG",
- "class": "logging.FileHandler",
- "formatter": "standard",
- "filename": "/home/opnfv/functest/results/functest.log"
- }
- },
- "loggers": {
- "": {
- "handlers": ["console", "file"],
- "level": "DEBUG",
- "propagate": "yes"
- }
- }
-}
diff --git a/functest/ci/prepare_env.py b/functest/ci/prepare_env.py
index e9a470f9c..8e17a4fcc 100755
--- a/functest/ci/prepare_env.py
+++ b/functest/ci/prepare_env.py
@@ -8,6 +8,8 @@
import argparse
import json
+import logging
+import logging.config
import os
import re
import subprocess
@@ -16,7 +18,6 @@ import fileinput
import yaml
-import functest.utils.functest_logger as ft_logger
import functest.utils.functest_utils as ft_utils
import functest.utils.openstack_utils as os_utils
from functest.utils.constants import CONST
@@ -27,13 +28,13 @@ from opnfv.deployment import factory
actions = ['start', 'check']
""" logging configuration """
-logger = ft_logger.Logger("prepare_env").getLogger()
+logger = logging.getLogger('functest.ci.prepare_env')
handler = None
# set the architecture to default
pod_arch = None
arch_filter = ['aarch64']
-CONFIG_FUNCTEST_PATH = CONST.CONFIG_FUNCTEST_YAML
+CONFIG_FUNCTEST_PATH = CONST.__getattribute__('CONFIG_FUNCTEST_YAML')
CONFIG_PATCH_PATH = os.path.join(os.path.dirname(
CONFIG_FUNCTEST_PATH), "config_patch.yaml")
CONFIG_AARCH64_PATCH_PATH = os.path.join(os.path.dirname(
@@ -65,63 +66,70 @@ def check_env_variables():
print_separator()
logger.info("Checking environment variables...")
- if CONST.INSTALLER_TYPE is None:
+ if CONST.__getattribute__('INSTALLER_TYPE') is None:
logger.warning("The env variable 'INSTALLER_TYPE' is not defined.")
- CONST.INSTALLER_TYPE = "undefined"
+ CONST.__setattr__('INSTALLER_TYPE', 'undefined')
else:
- if CONST.INSTALLER_TYPE not in opnfv_constants.INSTALLERS:
+ if (CONST.__getattribute__('INSTALLER_TYPE') not in
+ opnfv_constants.INSTALLERS):
logger.warning("INSTALLER_TYPE=%s is not a valid OPNFV installer. "
"Available OPNFV Installers are : %s. "
"Setting INSTALLER_TYPE=undefined."
- % (CONST.INSTALLER_TYPE,
+ % (CONST.__getattribute__('INSTALLER_TYPE'),
opnfv_constants.INSTALLERS))
- CONST.INSTALLER_TYPE = "undefined"
+ CONST.__setattr__('INSTALLER_TYPE', 'undefined')
else:
logger.info(" INSTALLER_TYPE=%s"
- % CONST.INSTALLER_TYPE)
+ % CONST.__getattribute__('INSTALLER_TYPE'))
- if CONST.INSTALLER_IP is None:
+ if CONST.__getattribute__('INSTALLER_IP') is None:
logger.warning("The env variable 'INSTALLER_IP' is not defined. "
"It is needed to fetch the OpenStack credentials. "
"If the credentials are not provided to the "
"container as a volume, please add this env variable "
"to the 'docker run' command.")
else:
- logger.info(" INSTALLER_IP=%s" % CONST.INSTALLER_IP)
+ logger.info(" INSTALLER_IP=%s" %
+ CONST.__getattribute__('INSTALLER_IP'))
- if CONST.DEPLOY_SCENARIO is None:
+ if CONST.__getattribute__('DEPLOY_SCENARIO') is None:
logger.warning("The env variable 'DEPLOY_SCENARIO' is not defined. "
"Setting CI_SCENARIO=undefined.")
- CONST.DEPLOY_SCENARIO = "undefined"
+ CONST.__setattr__('DEPLOY_SCENARIO', 'undefined')
else:
- logger.info(" DEPLOY_SCENARIO=%s" % CONST.DEPLOY_SCENARIO)
- if CONST.CI_DEBUG:
- logger.info(" CI_DEBUG=%s" % CONST.CI_DEBUG)
+ logger.info(" DEPLOY_SCENARIO=%s"
+ % CONST.__getattribute__('DEPLOY_SCENARIO'))
+ if CONST.__getattribute__('CI_DEBUG'):
+ logger.info(" CI_DEBUG=%s" % CONST.__getattribute__('CI_DEBUG'))
- if CONST.NODE_NAME:
- logger.info(" NODE_NAME=%s" % CONST.NODE_NAME)
+ if CONST.__getattribute__('NODE_NAME'):
+ logger.info(" NODE_NAME=%s" % CONST.__getattribute__('NODE_NAME'))
- if CONST.BUILD_TAG:
- logger.info(" BUILD_TAG=%s" % CONST.BUILD_TAG)
+ if CONST.__getattribute__('BUILD_TAG'):
+ logger.info(" BUILD_TAG=%s" % CONST.__getattribute__('BUILD_TAG'))
- if CONST.IS_CI_RUN:
- logger.info(" IS_CI_RUN=%s" % CONST.IS_CI_RUN)
+ if CONST.__getattribute__('IS_CI_RUN'):
+ logger.info(" IS_CI_RUN=%s" % CONST.__getattribute__('IS_CI_RUN'))
def get_deployment_handler():
global handler
global pod_arch
- installer_params_yaml = os.path.join(CONST.dir_repo_functest,
- 'functest/ci/installer_params.yaml')
- if (CONST.INSTALLER_IP and CONST.INSTALLER_TYPE and
- CONST.INSTALLER_TYPE in opnfv_constants.INSTALLERS):
+ installer_params_yaml = os.path.join(
+ CONST.__getattribute__('dir_repo_functest'),
+ 'functest/ci/installer_params.yaml')
+ if (CONST.__getattribute__('INSTALLER_IP') and
+ CONST.__getattribute__('INSTALLER_TYPE') and
+ CONST.__getattribute__('INSTALLER_TYPE') in
+ opnfv_constants.INSTALLERS):
try:
installer_params = ft_utils.get_parameter_from_yaml(
- CONST.INSTALLER_TYPE, installer_params_yaml)
+ CONST.__getattribute__('INSTALLER_TYPE'),
+ installer_params_yaml)
except ValueError as e:
logger.debug('Printing deployment info is not supported for %s' %
- CONST.INSTALLER_TYPE)
+ CONST.__getattribute__('INSTALLER_TYPE'))
logger.debug(e)
else:
user = installer_params.get('user', None)
@@ -129,8 +137,8 @@ def get_deployment_handler():
pkey = installer_params.get('pkey', None)
try:
handler = factory.Factory.get_handler(
- installer=CONST.INSTALLER_TYPE,
- installer_ip=CONST.INSTALLER_IP,
+ installer=CONST.__getattribute__('INSTALLER_TYPE'),
+ installer_ip=CONST.__getattribute__('INSTALLER_IP'),
installer_user=user,
installer_pwd=password,
pkey_file=pkey)
@@ -143,51 +151,62 @@ def get_deployment_handler():
def create_directories():
print_separator()
logger.info("Creating needed directories...")
- if not os.path.exists(CONST.dir_functest_conf):
- os.makedirs(CONST.dir_functest_conf)
- logger.info(" %s created." % CONST.dir_functest_conf)
+ if not os.path.exists(CONST.__getattribute__('dir_functest_conf')):
+ os.makedirs(CONST.__getattribute__('dir_functest_conf'))
+ logger.info(" %s created." %
+ CONST.__getattribute__('dir_functest_conf'))
else:
- logger.debug(" %s already exists."
- % CONST.dir_functest_conf)
+ logger.debug(" %s already exists." %
+ CONST.__getattribute__('dir_functest_conf'))
- if not os.path.exists(CONST.dir_functest_data):
- os.makedirs(CONST.dir_functest_data)
- logger.info(" %s created." % CONST.dir_functest_data)
+ if not os.path.exists(CONST.__getattribute__('dir_functest_data')):
+ os.makedirs(CONST.__getattribute__('dir_functest_data'))
+ logger.info(" %s created." %
+ CONST.__getattribute__('dir_functest_data'))
else:
- logger.debug(" %s already exists."
- % CONST.dir_functest_data)
+ logger.debug(" %s already exists." %
+ CONST.__getattribute__('dir_functest_data'))
+ if not os.path.exists(CONST.__getattribute__('dir_functest_images')):
+ os.makedirs(CONST.__getattribute__('dir_functest_images'))
+ logger.info(" %s created." %
+ CONST.__getattribute__('dir_functest_images'))
+ else:
+ logger.debug(" %s already exists." %
+ CONST.__getattribute__('dir_functest_images'))
def source_rc_file():
print_separator()
logger.info("Fetching RC file...")
- if CONST.openstack_creds is None:
+ if CONST.__getattribute__('openstack_creds') is None:
logger.warning("The environment variable 'creds' must be set and"
"pointing to the local RC file. Using default: "
"/home/opnfv/functest/conf/openstack.creds ...")
- os.path.join(CONST.dir_functest_conf, 'openstack.creds')
+ os.path.join(
+ CONST.__getattribute__('dir_functest_conf'), 'openstack.creds')
- if not os.path.isfile(CONST.openstack_creds):
+ if not os.path.isfile(CONST.__getattribute__('openstack_creds')):
logger.info("RC file not provided. "
"Fetching it from the installer...")
- if CONST.INSTALLER_IP is None:
- logger.error("The env variable CI_INSTALLER_IP must be provided in"
+ if CONST.__getattribute__('INSTALLER_IP')is None:
+ logger.error("The env variable 'INSTALLER_IP' must be provided in"
" order to fetch the credentials from the installer.")
raise Exception("Missing CI_INSTALLER_IP.")
- if CONST.INSTALLER_TYPE not in opnfv_constants.INSTALLERS:
+ if (CONST.__getattribute__('INSTALLER_TYPE') not in
+ opnfv_constants.INSTALLERS):
logger.error("Cannot fetch credentials. INSTALLER_TYPE=%s is "
"not a valid OPNFV installer. Available "
"installers are : %s." %
- (CONST.INSTALLER_TYPE,
+ (CONST.__getattribute__('INSTALLER_TYPE'),
opnfv_constants.INSTALLERS))
raise Exception("Wrong INSTALLER_TYPE.")
cmd = ("/home/opnfv/repos/releng/utils/fetch_os_creds.sh "
"-d %s -i %s -a %s"
- % (CONST.openstack_creds,
- CONST.INSTALLER_TYPE,
- CONST.INSTALLER_IP))
+ % (CONST.__getattribute__('openstack_creds'),
+ CONST.__getattribute__('INSTALLER_TYPE'),
+ CONST.__getattribute__('INSTALLER_IP')))
logger.debug("Executing command: %s" % cmd)
p = subprocess.Popen(cmd.split(), stdout=subprocess.PIPE)
output = p.communicate()[0]
@@ -196,22 +215,23 @@ def source_rc_file():
raise Exception("Failed to fetch credentials from installer.")
else:
logger.info("RC file provided in %s."
- % CONST.openstack_creds)
- if os.path.getsize(CONST.openstack_creds) == 0:
- raise Exception("The file %s is empty." % CONST.openstack_creds)
+ % CONST.__getattribute__('openstack_creds'))
+ if os.path.getsize(CONST.__getattribute__('openstack_creds')) == 0:
+ raise Exception("The file %s is empty." %
+ CONST.__getattribute__('openstack_creds'))
logger.info("Sourcing the OpenStack RC file...")
- os_utils.source_credentials(CONST.openstack_creds)
+ os_utils.source_credentials(CONST.__getattribute__('openstack_creds'))
for key, value in os.environ.iteritems():
if re.search("OS_", key):
if key == 'OS_AUTH_URL':
- CONST.OS_AUTH_URL = value
+ CONST.__setattr__('OS_AUTH_URL', value)
elif key == 'OS_USERNAME':
- CONST.OS_USERNAME = value
+ CONST.__setattr__('OS_USERNAME', value)
elif key == 'OS_TENANT_NAME':
- CONST.OS_TENANT_NAME = value
+ CONST.__setattr__('OS_TENANT_NAME', value)
elif key == 'OS_PASSWORD':
- CONST.OS_PASSWORD = value
+ CONST.__setattr__('OS_PASSWORD', value)
def patch_config_file():
@@ -228,7 +248,7 @@ def patch_file(patch_file_path):
updated = False
for key in patch_file:
- if key in CONST.DEPLOY_SCENARIO:
+ if key in CONST.__getattribute__('DEPLOY_SCENARIO'):
new_functest_yaml = dict(ft_utils.merge_dicts(
ft_utils.get_functest_yaml(), patch_file[key]))
updated = True
@@ -243,7 +263,8 @@ def patch_file(patch_file_path):
def verify_deployment():
print_separator()
logger.info("Verifying OpenStack services...")
- cmd = ("%s/functest/ci/check_os.sh" % CONST.dir_repo_functest)
+ cmd = ("%s/functest/ci/check_os.sh" %
+ CONST.__getattribute__('dir_repo_functest'))
logger.debug("Executing command: %s" % cmd)
p = subprocess.Popen(cmd, stdout=subprocess.PIPE, shell=True)
@@ -274,7 +295,7 @@ def install_rally():
cmd = "rally deployment destroy opnfv-rally"
ft_utils.execute_command(cmd, error_msg=(
"Deployment %s does not exist."
- % CONST.rally_deployment_name),
+ % CONST.__getattribute__('rally_deployment_name')),
verbose=False)
rally_conf = os_utils.get_credentials_for_rally()
@@ -282,7 +303,7 @@ def install_rally():
json.dump(rally_conf, fp)
cmd = ("rally deployment create "
"--file=rally_conf.json --name={0}"
- .format(CONST.rally_deployment_name))
+ .format(CONST.__getattribute__('rally_deployment_name')))
error_msg = "Problem while creating Rally deployment"
ft_utils.execute_command_raise(cmd, error_msg=error_msg)
@@ -304,17 +325,18 @@ def install_rally():
def install_tempest():
logger.info("Installing tempest from existing repo...")
cmd = ("rally verify list-verifiers | "
- "grep '{0}' | wc -l".format(CONST.tempest_deployment_name))
+ "grep '{0}' | wc -l".format(
+ CONST.__getattribute__('tempest_deployment_name')))
p = subprocess.Popen(cmd, stdout=subprocess.PIPE, shell=True)
while p.poll() is None:
line = p.stdout.readline().rstrip()
if str(line) == '0':
logger.debug("Tempest %s does not exist" %
- CONST.tempest_deployment_name)
+ CONST.__getattribute__('tempest_deployment_name'))
cmd = ("rally verify create-verifier --source {0} "
"--name {1} --type tempest --system-wide"
- .format(CONST.dir_repo_tempest,
- CONST.tempest_deployment_name))
+ .format(CONST.__getattribute__('dir_repo_tempest'),
+ CONST.__getattribute__('tempest_deployment_name')))
error_msg = "Problem while installing Tempest."
ft_utils.execute_command_raise(cmd, error_msg=error_msg)
@@ -331,10 +353,10 @@ def create_flavor():
def check_environment():
msg_not_active = "The Functest environment is not installed."
- if not os.path.isfile(CONST.env_active):
+ if not os.path.isfile(CONST.__getattribute__('env_active')):
raise Exception(msg_not_active)
- with open(CONST.env_active, "r") as env_file:
+ with open(CONST.__getattribute__('env_active'), "r") as env_file:
s = env_file.read()
if not re.search("1", s):
raise Exception(msg_not_active)
@@ -364,7 +386,7 @@ def main(**kwargs):
install_rally()
install_tempest()
create_flavor()
- with open(CONST.env_active, "w") as env_file:
+ with open(CONST.__getattribute__('env_active'), "w") as env_file:
env_file.write("1")
check_environment()
print_deployment_info()
@@ -377,6 +399,8 @@ def main(**kwargs):
if __name__ == '__main__':
+ logging.config.fileConfig(
+ CONST.__getattribute__('dir_functest_logging_cfg'))
parser = PrepareEnvParser()
args = parser.parse_args(sys.argv[1:])
sys.exit(main(**args))
diff --git a/functest/ci/run_tests.py b/functest/ci/run_tests.py
index e68901b89..76760096b 100755
--- a/functest/ci/run_tests.py
+++ b/functest/ci/run_tests.py
@@ -9,26 +9,26 @@
#
import argparse
-import datetime
import enum
import importlib
+import logging
+import logging.config
import os
import re
import sys
-import functest.ci.generate_report as generate_report
+import prettytable
+
import functest.ci.tier_builder as tb
import functest.core.testcase as testcase
-import functest.utils.functest_logger as ft_logger
import functest.utils.functest_utils as ft_utils
import functest.utils.openstack_clean as os_clean
import functest.utils.openstack_snapshot as os_snapshot
import functest.utils.openstack_utils as os_utils
from functest.utils.constants import CONST
-
-""" logging configuration """
-logger = ft_logger.Logger("run_tests").getLogger()
+# __name__ cannot be used here
+logger = logging.getLogger('functest.ci.run_tests')
class Result(enum.Enum):
@@ -40,6 +40,10 @@ class BlockingTestFailed(Exception):
pass
+class TestNotEnabled(Exception):
+ pass
+
+
class RunTestsParser(object):
def __init__(self):
@@ -75,7 +79,7 @@ def print_separator(str, count=45):
def source_rc_file():
- rc_file = CONST.openstack_creds
+ rc_file = CONST.__getattribute__('openstack_creds')
if not os.path.isfile(rc_file):
raise Exception("RC file %s does not exist..." % rc_file)
logger.debug("Sourcing the OpenStack RC file...")
@@ -83,13 +87,13 @@ def source_rc_file():
for key, value in os.environ.iteritems():
if re.search("OS_", key):
if key == 'OS_AUTH_URL':
- CONST.OS_AUTH_URL = value
+ CONST.__setattr__('OS_AUTH_URL', value)
elif key == 'OS_USERNAME':
- CONST.OS_USERNAME = value
+ CONST.__setattr__('OS_USERNAME', value)
elif key == 'OS_TENANT_NAME':
- CONST.OS_TENANT_NAME = value
+ CONST.__setattr__('OS_TENANT_NAME', value)
elif key == 'OS_PASSWORD':
- CONST.OS_PASSWORD = value
+ CONST.__setattr__('OS_PASSWORD', value)
def generate_os_snapshot():
@@ -100,13 +104,6 @@ def cleanup():
os_clean.main()
-def update_test_info(test_name, result, duration):
- for test in GlobalVariables.EXECUTED_TEST_CASES:
- if test['test_name'] == test_name:
- test.update({"result": result,
- "duration": duration})
-
-
def get_run_dict(testname):
try:
dict = ft_utils.get_dict_by_test(testname)
@@ -121,8 +118,9 @@ def get_run_dict(testname):
def run_test(test, tier_name, testcases=None):
- result_str = "PASS"
- start = datetime.datetime.now()
+ if not test.is_enabled():
+ raise TestNotEnabled("The test case {} is not enabled"
+ .format(test.get_name()))
test_name = test.get_name()
logger.info("\n") # blank line
print_separator("=")
@@ -146,7 +144,7 @@ def run_test(test, tier_name, testcases=None):
cls = getattr(module, run_dict['class'])
test_dict = ft_utils.get_dict_by_test(test_name)
test_case = cls(**test_dict)
-
+ GlobalVariables.EXECUTED_TEST_CASES.append(test_case)
try:
kwargs = run_dict['args']
result = test_case.run(**kwargs)
@@ -155,7 +153,8 @@ def run_test(test, tier_name, testcases=None):
if result == testcase.TestCase.EX_OK:
if GlobalVariables.REPORT_FLAG:
test_case.push_to_db()
- result = test_case.check_result()
+ result = test_case.is_successful()
+ logger.info("Test result:\n\n%s\n", test_case)
except ImportError:
logger.exception("Cannot import module {}".format(
run_dict['module']))
@@ -167,27 +166,13 @@ def run_test(test, tier_name, testcases=None):
if test.needs_clean() and GlobalVariables.CLEAN_FLAG:
cleanup()
-
- end = datetime.datetime.now()
- duration = (end - start).seconds
- duration_str = ("%02d:%02d" % divmod(duration, 60))
- logger.info("Test execution time: %s" % duration_str)
-
- if result != 0:
+ if result != testcase.TestCase.EX_OK:
logger.error("The test case '%s' failed. " % test_name)
GlobalVariables.OVERALL_RESULT = Result.EX_ERROR
- result_str = "FAIL"
-
if test.is_blocking():
- if not testcases or testcases == "all":
- # if it is a single test we don't print the whole results table
- update_test_info(test_name, result_str, duration_str)
- generate_report.main(GlobalVariables.EXECUTED_TEST_CASES)
raise BlockingTestFailed("The test case {} failed and is blocking"
.format(test.get_name()))
- update_test_info(test_name, result_str, duration_str)
-
def run_tier(tier):
tier_name = tier.get_name()
@@ -211,27 +196,24 @@ def run_all(tiers):
for tier in tiers.get_tiers():
if (len(tier.get_tests()) != 0 and
- re.search(CONST.CI_LOOP, tier.get_ci_loop()) is not None):
+ re.search(CONST.__getattribute__('CI_LOOP'),
+ tier.get_ci_loop()) is not None):
tiers_to_run.append(tier)
summary += ("\n - %s:\n\t %s"
% (tier.get_name(),
tier.get_test_names()))
logger.info("Tests to be executed:%s" % summary)
- GlobalVariables.EXECUTED_TEST_CASES = generate_report.init(tiers_to_run)
for tier in tiers_to_run:
run_tier(tier)
- generate_report.main(GlobalVariables.EXECUTED_TEST_CASES)
-
def main(**kwargs):
- CI_INSTALLER_TYPE = CONST.INSTALLER_TYPE
- CI_SCENARIO = CONST.DEPLOY_SCENARIO
-
file = CONST.functest_testcases_yaml
- _tiers = tb.TierBuilder(CI_INSTALLER_TYPE, CI_SCENARIO, file)
+ _tiers = tb.TierBuilder(CONST.__getattribute__('INSTALLER_TYPE'),
+ CONST.__getattribute__('DEPLOY_SCENARIO'),
+ file)
if kwargs['noclean']:
GlobalVariables.CLEAN_FLAG = False
@@ -243,12 +225,10 @@ def main(**kwargs):
if kwargs['test']:
source_rc_file()
if _tiers.get_tier(kwargs['test']):
- GlobalVariables.EXECUTED_TEST_CASES = generate_report.init(
- [_tiers.get_tier(kwargs['test'])])
run_tier(_tiers.get_tier(kwargs['test']))
elif _tiers.get_test(kwargs['test']):
run_test(_tiers.get_test(kwargs['test']),
- _tiers.get_tier(kwargs['test']),
+ _tiers.get_tier_name(kwargs['test']),
kwargs['test'])
elif kwargs['test'] == "all":
run_all(_tiers)
@@ -256,7 +236,8 @@ def main(**kwargs):
logger.error("Unknown test case or tier '%s', "
"or not supported by "
"the given scenario '%s'."
- % (kwargs['test'], CI_SCENARIO))
+ % (kwargs['test'],
+ CONST.__getattribute__('DEPLOY_SCENARIO')))
logger.debug("Available tiers are:\n\n%s"
% _tiers)
return Result.EX_ERROR
@@ -265,11 +246,33 @@ def main(**kwargs):
except Exception as e:
logger.error(e)
GlobalVariables.OVERALL_RESULT = Result.EX_ERROR
+
+ msg = prettytable.PrettyTable(
+ header_style='upper', padding_width=5,
+ field_names=['env var', 'value'])
+ for env_var in ['INSTALLER_TYPE', 'DEPLOY_SCENARIO', 'BUILD_TAG',
+ 'CI_LOOP']:
+ msg.add_row([env_var, CONST.__getattribute__(env_var)])
+ logger.info("Deployment description: \n\n%s\n", msg)
+
+ msg = prettytable.PrettyTable(
+ header_style='upper', padding_width=5,
+ field_names=['test case', 'project', 'tier', 'duration', 'result'])
+ for test_case in GlobalVariables.EXECUTED_TEST_CASES:
+ result = 'PASS' if(test_case.is_successful(
+ ) == test_case.EX_OK) else 'FAIL'
+ msg.add_row([test_case.case_name, test_case.project_name,
+ _tiers.get_tier_name(test_case.case_name),
+ test_case.get_duration(), result])
+ logger.info("FUNCTEST REPORT: \n\n%s\n", msg)
+
logger.info("Execution exit value: %s" % GlobalVariables.OVERALL_RESULT)
return GlobalVariables.OVERALL_RESULT
if __name__ == '__main__':
+ logging.config.fileConfig(
+ CONST.__getattribute__('dir_functest_logging_cfg'))
parser = RunTestsParser()
args = parser.parse_args(sys.argv[1:])
sys.exit(main(**args).value)
diff --git a/functest/ci/testcases.yaml b/functest/ci/testcases.yaml
index 7009e910c..d98a2de23 100644
--- a/functest/ci/testcases.yaml
+++ b/functest/ci/testcases.yaml
@@ -19,7 +19,6 @@ tiers:
simple queries. When the config value of
snaps.use_keystone is True, functest must have access to
the cloud's private network.
-
dependencies:
installer: '^((?!netvirt).)*$'
scenario: ''
@@ -39,13 +38,13 @@ tiers:
simple queries. When the config value of
snaps.use_keystone is True, functest must have access to
the cloud's private network.
-
dependencies:
installer: '^((?!netvirt).)*$'
scenario: ''
run:
module: 'functest.opnfv_tests.openstack.snaps.api_check'
class: 'ApiCheck'
+
-
case_name: snaps_health_check
project_name: functest
@@ -63,6 +62,7 @@ tiers:
run:
module: 'functest.opnfv_tests.openstack.snaps.health_check'
class: 'HealthCheck'
+
-
name: smoke
order: 1
@@ -266,6 +266,7 @@ tiers:
testcases:
-
case_name: promise
+ enabled: false
project_name: promise
criteria: 100
blocking: false
@@ -283,6 +284,7 @@ tiers:
-
case_name: doctor-notification
+ enabled: false
project_name: doctor
criteria: 100
blocking: false
@@ -300,6 +302,7 @@ tiers:
-
case_name: bgpvpn
+ enabled: false
project_name: sdnvpn
criteria: 100
blocking: false
@@ -317,6 +320,7 @@ tiers:
-
case_name: security_scan
+ enabled: false
project_name: securityscanning
criteria: 100
blocking: false
@@ -334,6 +338,7 @@ tiers:
-
case_name: copper
+ enabled: false
project_name: copper
criteria: 100
blocking: false
@@ -351,6 +356,7 @@ tiers:
-
case_name: multisite
+ enabled: false
project_name: multisite
criteria: 100
blocking: false
@@ -363,8 +369,10 @@ tiers:
run:
module: 'functest.opnfv_tests.openstack.tempest.tempest'
class: 'TempestMultisite'
+
-
case_name: functest-odl-sfc
+ enabled: false
project_name: sfc
criteria: 100
blocking: false
@@ -379,8 +387,10 @@ tiers:
class: 'BashFeature'
args:
cmd: 'cd /home/opnfv/repos/sfc/sfc/tests/functest && python ./run_tests.py'
+
-
case_name: onos_sfc
+ enabled: false
project_name: functest
criteria: 100
blocking: true
@@ -393,8 +403,10 @@ tiers:
run:
module: 'functest.opnfv_tests.sdn.onos.onos'
class: 'OnosSfc'
+
-
case_name: parser-basics
+ enabled: false
project_name: parser
criteria: 100
blocking: false
@@ -409,8 +421,10 @@ tiers:
class: 'BashFeature'
args:
cmd: 'cd /home/opnfv/repos/parser/tests && ./functest_run.sh'
+
-
case_name: domino-multinode
+ enabled: false
project_name: domino
criteria: 100
blocking: false
@@ -425,8 +439,10 @@ tiers:
class: 'BashFeature'
args:
cmd: 'cd /home/opnfv/repos/domino && ./tests/run_multinode.sh'
+
-
case_name: gluon_vping
+ enabled: false
project_name: netready
criteria: 100
blocking: false
@@ -441,8 +457,10 @@ tiers:
class: 'BashFeature'
args:
cmd: 'cd /home/opnfv/repos/netready/test/functest && python ./gluon-test-suite.py'
+
-
case_name: barometercollectd
+ enabled: false
project_name: barometer
criteria: 100
blocking: false
@@ -458,6 +476,7 @@ tiers:
run:
module: 'functest.opnfv_tests.features.barometer'
class: 'BarometerCollectd'
+
-
name: components
order: 3
@@ -481,6 +500,7 @@ tiers:
run:
module: 'functest.opnfv_tests.openstack.tempest.tempest'
class: 'TempestFullParallel'
+
-
case_name: tempest_custom
project_name: functest
@@ -499,6 +519,7 @@ tiers:
run:
module: 'functest.opnfv_tests.openstack.tempest.tempest'
class: 'TempestCustom'
+
-
case_name: rally_full
project_name: functest
@@ -537,22 +558,26 @@ tiers:
run:
module: 'functest.opnfv_tests.vnf.ims.cloudify_ims'
class: 'CloudifyIms'
-# -
-# case_name: aaa
-# project_name: functest
-# criteria: 100
-# blocking: false
-# clean_flag: true
-# description: >-
-# Test suite from Parser project.
-# dependencies:
-# installer: ''
-# scenario: ''
-# run:
-# module: 'functest.opnfv_tests.vnf.aaa.aaa'
-# class: 'AaaVnf'
+
+ -
+ case_name: aaa
+ enabled: false
+ project_name: functest
+ criteria: 100
+ blocking: false
+ clean_flag: true
+ description: >-
+ Test suite from Parser project.
+ dependencies:
+ installer: ''
+ scenario: ''
+ run:
+ module: 'functest.opnfv_tests.vnf.aaa.aaa'
+ class: 'AaaVnf'
+
-
case_name: orchestra_ims
+ enabled: false
project_name: functest
criteria: 100
blocking: false
@@ -568,6 +593,7 @@ tiers:
-
case_name: opera_vims
+ enabled: false
project_name: opera
criteria: 100
blocking: false
@@ -583,6 +609,7 @@ tiers:
-
case_name: vyos_vrouter
+ enabled: false
project_name: functest
criteria: 100
blocking: false
diff --git a/functest/ci/tier_builder.py b/functest/ci/tier_builder.py
index 44b272584..12562f09c 100644
--- a/functest/ci/tier_builder.py
+++ b/functest/ci/tier_builder.py
@@ -47,12 +47,15 @@ class TierBuilder(object):
dep = th.Dependency(installer, scenario)
testcase = th.TestCase(name=dic_testcase['case_name'],
+ enabled=dic_testcase.get(
+ 'enabled', True),
dependency=dep,
criteria=dic_testcase['criteria'],
blocking=dic_testcase['blocking'],
clean_flag=dic_testcase['clean_flag'],
description=dic_testcase['description'])
- if testcase.is_compatible(self.ci_installer, self.ci_scenario):
+ if (testcase.is_compatible(self.ci_installer, self.ci_scenario)
+ and testcase.is_enabled()):
tier.add_test(testcase)
self.tier_objects.append(tier)
@@ -72,6 +75,12 @@ class TierBuilder(object):
return self.tier_objects[i]
return None
+ def get_tier_name(self, test_name):
+ for i in range(0, len(self.tier_objects)):
+ if self.tier_objects[i].is_test(test_name):
+ return self.tier_objects[i].name
+ return None
+
def get_test(self, test_name):
for i in range(0, len(self.tier_objects)):
if self.tier_objects[i].is_test(test_name):
diff --git a/functest/ci/tier_handler.py b/functest/ci/tier_handler.py
index fe7372a38..36ce245e7 100644
--- a/functest/ci/tier_handler.py
+++ b/functest/ci/tier_handler.py
@@ -105,12 +105,14 @@ class Tier(object):
class TestCase(object):
def __init__(self, name,
+ enabled,
dependency,
criteria,
blocking,
clean_flag,
description=""):
self.name = name
+ self.enabled = enabled
self.dependency = dependency
self.criteria = criteria
self.blocking = blocking
@@ -138,6 +140,9 @@ class TestCase(object):
def get_name(self):
return self.name
+ def is_enabled(self):
+ return self.enabled
+
def get_criteria(self):
return self.criteria
diff --git a/functest/cli/cli_base.py b/functest/cli/cli_base.py
index cc697ed7e..2104e125c 100644
--- a/functest/cli/cli_base.py
+++ b/functest/cli/cli_base.py
@@ -8,11 +8,14 @@
#
import click
+import logging.config
from functest.cli.commands.cli_env import CliEnv
from functest.cli.commands.cli_os import CliOpenStack
from functest.cli.commands.cli_testcase import CliTestcase
from functest.cli.commands.cli_tier import CliTier
+from functest.utils.constants import CONST
+
CONTEXT_SETTINGS = dict(help_option_names=['-h', '--help'])
@@ -20,7 +23,8 @@ CONTEXT_SETTINGS = dict(help_option_names=['-h', '--help'])
@click.group(context_settings=CONTEXT_SETTINGS)
@click.version_option(version='opnfv colorado.0.1 ')
def cli():
- pass
+ logging.config.fileConfig(
+ CONST.__getattribute__('dir_functest_logging_cfg'))
_env = CliEnv()
diff --git a/functest/cli/commands/cli_env.py b/functest/cli/commands/cli_env.py
index 14ad01bfc..f5ba4b342 100644
--- a/functest/cli/commands/cli_env.py
+++ b/functest/cli/commands/cli_env.py
@@ -28,7 +28,7 @@ class CliEnv(object):
"it again? [y|n]\n")
while True:
if answer.lower() in ["y", "yes"]:
- os.remove(CONST.env_active)
+ os.remove(CONST.__getattribute__('env_active'))
break
elif answer.lower() in ["n", "no"]:
return
@@ -36,19 +36,19 @@ class CliEnv(object):
answer = raw_input("Invalid answer. Please type [y|n]\n")
cmd = ("python %s/functest/ci/prepare_env.py start" %
- CONST.dir_repo_functest)
+ CONST.__getattribute__('dir_repo_functest'))
ft_utils.execute_command(cmd)
def show(self):
def _get_value(attr, default='Unknown'):
return attr if attr else default
- install_type = _get_value(CONST.INSTALLER_TYPE)
- installer_ip = _get_value(CONST.INSTALLER_IP)
+ install_type = _get_value(CONST.__getattribute__('INSTALLER_TYPE'))
+ installer_ip = _get_value(CONST.__getattribute__('INSTALLER_IP'))
installer_info = ("%s, %s" % (install_type, installer_ip))
- scenario = _get_value(CONST.DEPLOY_SCENARIO)
- node = _get_value(CONST.NODE_NAME)
- repo_h = git.Repo(CONST.dir_repo_functest).head
+ scenario = _get_value(CONST.__getattribute__('DEPLOY_SCENARIO'))
+ node = _get_value(CONST.__getattribute__('NODE_NAME'))
+ repo_h = git.Repo(CONST.__getattribute__('dir_repo_functest')).head
if repo_h.is_detached:
git_branch = 'detached from FETCH_HEAD'
git_hash = repo_h.commit.hexsha
@@ -56,8 +56,8 @@ class CliEnv(object):
branch = repo_h.reference
git_branch = branch.name
git_hash = branch.commit.hexsha
- is_debug = _get_value(CONST.CI_DEBUG, 'false')
- build_tag = CONST.BUILD_TAG
+ is_debug = _get_value(CONST.__getattribute__('CI_DEBUG'), 'false')
+ build_tag = CONST.__getattribute__('BUILD_TAG')
if build_tag is not None:
build_tag = build_tag.lstrip(
"jenkins-").lstrip("functest").lstrip("-")
@@ -84,7 +84,7 @@ class CliEnv(object):
def status(self, verbose=True):
ret_val = 0
- if not os.path.isfile(CONST.env_active):
+ if not os.path.isfile(CONST.__getattribute__('env_active')):
if verbose:
click.echo("Functest environment is not installed.\n")
ret_val = 1
diff --git a/functest/cli/commands/cli_os.py b/functest/cli/commands/cli_os.py
index f85f4041f..e54eb423a 100644
--- a/functest/cli/commands/cli_os.py
+++ b/functest/cli/commands/cli_os.py
@@ -21,11 +21,11 @@ import functest.utils.openstack_snapshot as os_snapshot
class CliOpenStack(object):
def __init__(self):
- self.os_auth_url = CONST.OS_AUTH_URL
+ self.os_auth_url = CONST.__getattribute__('OS_AUTH_URL')
self.endpoint_ip = None
self.endpoint_port = None
- self.openstack_creds = CONST.openstack_creds
- self.snapshot_file = CONST.openstack_snapshot_file
+ self.openstack_creds = CONST.__getattribute__('openstack_creds')
+ self.snapshot_file = CONST.__getattribute__('openstack_snapshot_file')
if self.os_auth_url:
self.endpoint_ip = self.os_auth_url.rsplit("/")[2].rsplit(":")[0]
self.endpoint_port = self.os_auth_url.rsplit("/")[2].rsplit(":")[1]
@@ -59,16 +59,16 @@ class CliOpenStack(object):
else:
answer = raw_input("Invalid answer. Please type [y|n]\n")
- installer_type = CONST.INSTALLER_TYPE
+ installer_type = CONST.__getattribute__('INSTALLER_TYPE')
if installer_type is None:
click.echo("The environment variable 'INSTALLER_TYPE' is not"
"defined. Please export it")
- installer_ip = CONST.INSTALLER_IP
+ installer_ip = CONST.__getattribute__('INSTALLER_IP')
if installer_ip is None:
click.echo("The environment variable 'INSTALLER_IP' is not"
"defined. Please export it")
cmd = ("%s/releng/utils/fetch_os_creds.sh -d %s -i %s -a %s"
- % (CONST.dir_repos,
+ % (CONST.__getattribute__('dir_repos'),
self.openstack_creds,
installer_type,
installer_ip))
@@ -78,7 +78,8 @@ class CliOpenStack(object):
def check(self):
self.ping_endpoint()
- cmd = CONST.dir_repo_functest + "/functest/ci/check_os.sh"
+ cmd = os.path.join(CONST.__getattribute__('dir_repo_functest'),
+ "functest/ci/check_os.sh")
ft_utils.execute_command(cmd, verbose=False)
def snapshot_create(self):
diff --git a/functest/cli/commands/cli_testcase.py b/functest/cli/commands/cli_testcase.py
index 6644a0c29..3d3f1cb3e 100644
--- a/functest/cli/commands/cli_testcase.py
+++ b/functest/cli/commands/cli_testcase.py
@@ -22,9 +22,10 @@ import functest.utils.functest_vacation as vacation
class CliTestcase(object):
def __init__(self):
- self.tiers = tb.TierBuilder(CONST.INSTALLER_TYPE,
- CONST.DEPLOY_SCENARIO,
- CONST.functest_testcases_yaml)
+ self.tiers = tb.TierBuilder(
+ CONST.__getattribute__('INSTALLER_TYPE'),
+ CONST.__getattribute__('DEPLOY_SCENARIO'),
+ CONST.__getattribute__('functest_testcases_yaml'))
def list(self):
summary = ""
@@ -52,12 +53,14 @@ class CliTestcase(object):
if testname == 'vacation':
vacation.main()
- elif not os.path.isfile(CONST.env_active):
+ elif not os.path.isfile(CONST.__getattribute__('env_active')):
click.echo("Functest environment is not ready. "
"Run first 'functest env prepare'")
else:
tests = testname.split(",")
for test in tests:
cmd = ("python %s/functest/ci/run_tests.py "
- "%s -t %s" % (CONST.dir_repo_functest, flags, test))
+ "%s -t %s" %
+ (CONST.__getattribute__('dir_repo_functest'),
+ flags, test))
ft_utils.execute_command(cmd)
diff --git a/functest/cli/commands/cli_tier.py b/functest/cli/commands/cli_tier.py
index 012b11d0e..531f0ff96 100644
--- a/functest/cli/commands/cli_tier.py
+++ b/functest/cli/commands/cli_tier.py
@@ -21,9 +21,10 @@ import functest.utils.functest_utils as ft_utils
class CliTier(object):
def __init__(self):
- self.tiers = tb.TierBuilder(CONST.INSTALLER_TYPE,
- CONST.DEPLOY_SCENARIO,
- CONST.functest_testcases_yaml)
+ self.tiers = tb.TierBuilder(
+ CONST.__getattribute__('INSTALLER_TYPE'),
+ CONST.__getattribute__('DEPLOY_SCENARIO'),
+ CONST.__getattribute__('functest_testcases_yaml'))
def list(self):
summary = ""
@@ -62,10 +63,12 @@ class CliTier(object):
if report:
flags += "-r "
- if not os.path.isfile(CONST.env_active):
+ if not os.path.isfile(CONST.__getattribute__('env_active')):
click.echo("Functest environment is not ready. "
"Run first 'functest env prepare'")
else:
cmd = ("python %s/functest/ci/run_tests.py "
- "%s -t %s" % (CONST.dir_repo_functest, flags, tiername))
+ "%s -t %s" %
+ (CONST.__getattribute__('dir_repo_functest'),
+ flags, tiername))
ft_utils.execute_command(cmd)
diff --git a/functest/core/feature.py b/functest/core/feature.py
index d65f5a3c1..140c9bb2e 100644
--- a/functest/core/feature.py
+++ b/functest/core/feature.py
@@ -13,11 +13,11 @@ Feature is considered as TestCase offered by Third-party. It offers
helpers to run any python method or any bash command.
"""
+import logging
import time
import functest.core.testcase as base
import functest.utils.functest_utils as ft_utils
-import functest.utils.functest_logger as ft_logger
from functest.utils.constants import CONST
__author__ = ("Serena Feng <feng.xiaowei@zte.com.cn>, "
@@ -27,11 +27,12 @@ __author__ = ("Serena Feng <feng.xiaowei@zte.com.cn>, "
class Feature(base.TestCase):
"""Base model for single feature."""
+ __logger = logging.getLogger(__name__)
+
def __init__(self, **kwargs):
super(Feature, self).__init__(**kwargs)
self.result_file = "{}/{}.log".format(
- CONST.__getattribute__('dir_results'), self.project_name)
- self.logger = ft_logger.Logger(self.project_name).getLogger()
+ CONST.__getattribute__('dir_results'), self.case_name)
def execute(self, **kwargs):
"""Execute the Python method.
@@ -82,10 +83,9 @@ class Feature(base.TestCase):
ft_utils.logger_test_results(
self.project_name, self.case_name,
self.result, self.details)
- self.logger.info("%s %s", self.project_name, self.result)
except Exception: # pylint: disable=broad-except
- self.logger.exception("%s FAILED", self.project_name)
- self.logger.info("Test result is stored in '%s'", self.result_file)
+ self.__logger.exception("%s FAILED", self.project_name)
+ self.__logger.info("Test result is stored in '%s'", self.result_file)
self.stop_time = time.time()
return exit_code
@@ -93,6 +93,8 @@ class Feature(base.TestCase):
class BashFeature(Feature):
"""Class designed to run any bash command."""
+ __logger = logging.getLogger(__name__)
+
def execute(self, **kwargs):
"""Execute the cmd passed as arg
@@ -108,7 +110,7 @@ class BashFeature(Feature):
cmd = kwargs["cmd"]
ret = ft_utils.execute_command(cmd, output_file=self.result_file)
except KeyError:
- self.logger.error("Please give cmd as arg. kwargs: %s", kwargs)
+ self.__logger.error("Please give cmd as arg. kwargs: %s", kwargs)
except Exception: # pylint: disable=broad-except
- self.logger.exception("Execute cmd: %s failed", cmd)
+ self.__logger.exception("Execute cmd: %s failed", cmd)
return ret
diff --git a/functest/core/pytest_suite_runner.py b/functest/core/pytest_suite_runner.py
index 8b5da05ef..a6e476600 100644
--- a/functest/core/pytest_suite_runner.py
+++ b/functest/core/pytest_suite_runner.py
@@ -5,26 +5,46 @@
#
# http://www.apache.org/licenses/LICENSE-2.0
-import testcase as base
-import unittest
+# pylint: disable=missing-docstring
+
+import logging
import time
+import unittest
+import six
-class PyTestSuiteRunner(base.TestCase):
+from functest.core import testcase
+
+
+class PyTestSuiteRunner(testcase.TestCase):
"""
This superclass is designed to execute pre-configured unittest.TestSuite()
objects
"""
+
def __init__(self, **kwargs):
super(PyTestSuiteRunner, self).__init__(**kwargs)
self.suite = None
+ self.logger = logging.getLogger(__name__)
def run(self, **kwargs):
"""
Starts test execution from the functest framework
"""
+ try:
+ name = kwargs["name"]
+ try:
+ self.suite = unittest.TestLoader().loadTestsFromName(name)
+ except ImportError:
+ self.logger.error("Can not import %s", name)
+ return testcase.TestCase.EX_RUN_ERROR
+ except KeyError:
+ pass
self.start_time = time.time()
- result = unittest.TextTestRunner(verbosity=2).run(self.suite)
+ stream = six.StringIO()
+ result = unittest.TextTestRunner(
+ stream=stream, verbosity=2).run(self.suite)
+ self.logger.debug("\n\n%s", stream.getvalue())
self.stop_time = time.time()
if result.errors:
@@ -44,14 +64,14 @@ class PyTestSuiteRunner(base.TestCase):
# we shall distinguish Execution Error from FAIL results
# TestCase.EX_RUN_ERROR means that the test case was not run
# not that it was run but the result was FAIL
- exit_code = base.TestCase.EX_OK
- if ((result.errors and len(result.errors) > 0)
- or (result.failures and len(result.failures) > 0)):
- self.logger.info("%s FAILED" % self.case_name)
- self.result = 'FAIL'
+ exit_code = testcase.TestCase.EX_OK
+ if ((result.errors and len(result.errors) > 0) or
+ (result.failures and len(result.failures) > 0)):
+ self.logger.info("%s FAILED", self.case_name)
+ self.result = 0
else:
- self.logger.info("%s OK" % self.case_name)
- self.result = 'PASS'
+ self.logger.info("%s OK", self.case_name)
+ self.result = 100
self.details = {}
return exit_code
diff --git a/functest/core/testcase.py b/functest/core/testcase.py
index 3f191b407..431615250 100644
--- a/functest/core/testcase.py
+++ b/functest/core/testcase.py
@@ -9,9 +9,11 @@
"""Define the parent class of all Functest TestCases."""
+import logging
import os
-import functest.utils.functest_logger as ft_logger
+import prettytable
+
import functest.utils.functest_utils as ft_utils
__author__ = "Cedric Ollivier <cedric.ollivier@orange.com>"
@@ -32,18 +34,53 @@ class TestCase(object):
EX_TESTCASE_FAILED = os.EX_SOFTWARE - 2
"""results are false"""
- logger = ft_logger.Logger(__name__).getLogger()
+ __logger = logging.getLogger(__name__)
def __init__(self, **kwargs):
self.details = {}
self.project_name = kwargs.get('project_name', 'functest')
self.case_name = kwargs.get('case_name', '')
self.criteria = kwargs.get('criteria', 100)
- self.result = ""
- self.start_time = ""
- self.stop_time = ""
+ self.result = 0
+ self.start_time = 0
+ self.stop_time = 0
+
+ def __str__(self):
+ try:
+ assert self.project_name
+ assert self.case_name
+ result = 'PASS' if(self.is_successful(
+ ) == TestCase.EX_OK) else 'FAIL'
+ msg = prettytable.PrettyTable(
+ header_style='upper', padding_width=5,
+ field_names=['test case', 'project', 'duration',
+ 'result'])
+ msg.add_row([self.case_name, self.project_name,
+ self.get_duration(), result])
+ return msg.get_string()
+ except AssertionError:
+ self.__logger.error("We cannot print invalid objects")
+ return super(TestCase, self).__str__()
+
+ def get_duration(self):
+ """Return the duration of the test case.
+
+ Returns:
+ duration if start_time and stop_time are set
+ "XX:XX" otherwise.
+ """
+ try:
+ assert self.start_time
+ assert self.stop_time
+ if self.stop_time < self.start_time:
+ return "XX:XX"
+ return "{0[0]:02.0f}:{0[1]:02.0f}".format(divmod(
+ self.stop_time - self.start_time, 60))
+ except Exception: # pylint: disable=broad-except
+ self.__logger.error("Please run test before getting the duration")
+ return "XX:XX"
- def check_result(self):
+ def is_successful(self):
"""Interpret the result of the test case.
It allows getting the result of TestCase. It completes run()
@@ -57,7 +94,9 @@ class TestCase(object):
"""
try:
assert self.criteria
- if isinstance(self.result, int) and isinstance(self.criteria, int):
+ assert self.result is not None
+ if (not isinstance(self.result, str) and
+ not isinstance(self.criteria, str)):
if self.result >= self.criteria:
return TestCase.EX_OK
else:
@@ -65,12 +104,12 @@ class TestCase(object):
# It must be removed as soon as TestCase subclasses
# stop setting result = 'PASS' or 'FAIL'.
# In this case criteria is unread.
- self.logger.warning(
+ self.__logger.warning(
"Please update result which must be an int!")
if self.result == 'PASS':
return TestCase.EX_OK
except AssertionError:
- self.logger.error("Please run test before checking the results")
+ self.__logger.error("Please run test before checking the results")
return TestCase.EX_TESTCASE_FAILED
def run(self, **kwargs):
@@ -96,7 +135,7 @@ class TestCase(object):
TestCase.EX_RUN_ERROR.
"""
# pylint: disable=unused-argument
- self.logger.error("Run must be implemented")
+ self.__logger.error("Run must be implemented")
return TestCase.EX_RUN_ERROR
def push_to_db(self):
@@ -123,16 +162,17 @@ class TestCase(object):
assert self.case_name
assert self.start_time
assert self.stop_time
- pub_result = 'PASS' if self.check_result(
+ pub_result = 'PASS' if self.is_successful(
) == TestCase.EX_OK else 'FAIL'
if ft_utils.push_results_to_db(
self.project_name, self.case_name, self.start_time,
self.stop_time, pub_result, self.details):
- self.logger.info("The results were successfully pushed to DB")
+ self.__logger.info(
+ "The results were successfully pushed to DB")
return TestCase.EX_OK
else:
- self.logger.error("The results cannot be pushed to DB")
+ self.__logger.error("The results cannot be pushed to DB")
return TestCase.EX_PUSH_TO_DB_ERROR
except Exception: # pylint: disable=broad-except
- self.logger.exception("The results cannot be pushed to DB")
+ self.__logger.exception("The results cannot be pushed to DB")
return TestCase.EX_PUSH_TO_DB_ERROR
diff --git a/functest/core/vnf_base.py b/functest/core/vnf.py
index fe4e427fa..5667b2997 100644
--- a/functest/core/vnf_base.py
+++ b/functest/core/vnf.py
@@ -8,30 +8,30 @@
# http://www.apache.org/licenses/LICENSE-2.0
import inspect
+import logging
import time
import functest.core.testcase as base
from functest.utils.constants import CONST
-import functest.utils.functest_logger as ft_logger
import functest.utils.functest_utils as ft_utils
import functest.utils.openstack_utils as os_utils
-class VnfOnBoardingBase(base.TestCase):
+class VnfOnBoarding(base.TestCase):
- logger = ft_logger.Logger(__name__).getLogger()
+ __logger = logging.getLogger(__name__)
def __init__(self, **kwargs):
- super(VnfOnBoardingBase, self).__init__(**kwargs)
+ super(VnfOnBoarding, self).__init__(**kwargs)
self.repo = kwargs.get('repo', '')
self.cmd = kwargs.get('cmd', '')
self.details = {}
- self.result_dir = CONST.dir_results
+ self.result_dir = CONST.__getattribute__('dir_results')
self.details_step_mapping = dict(
- deploy_orchestrator='orchestrator',
- deploy_vnf='vnf',
- test_vnf='test_vnf',
- prepare='prepare_env')
+ deploy_orchestrator='orchestrator',
+ deploy_vnf='vnf',
+ test_vnf='test_vnf',
+ prepare='prepare_env')
self.details['prepare_env'] = {}
self.details['orchestrator'] = {}
self.details['vnf'] = {}
@@ -44,28 +44,28 @@ class VnfOnBoardingBase(base.TestCase):
'vnf_{}_tenant_description'.format(self.case_name))
except Exception:
# raise Exception("Unknown VNF case=" + self.case_name)
- self.logger.error("Unknown VNF case={}".format(self.case_name))
+ self.__logger.error("Unknown VNF case={}".format(self.case_name))
try:
self.images = CONST.__getattribute__(
'vnf_{}_tenant_images'.format(self.case_name))
except Exception:
- self.logger.warn("No tenant image defined for this VNF")
+ self.__logger.warn("No tenant image defined for this VNF")
def execute(self):
self.start_time = time.time()
# Prepare the test (Create Tenant, User, ...)
try:
- self.logger.info("Create VNF Onboarding environment")
+ self.__logger.info("Create VNF Onboarding environment")
self.prepare()
except Exception:
- self.logger.error("Error during VNF Onboarding environment" +
- "creation", exc_info=True)
+ self.__logger.error("Error during VNF Onboarding environment"
+ "creation", exc_info=True)
return base.TestCase.EX_TESTCASE_FAILED
# Deploy orchestrator
try:
- self.logger.info("Deploy orchestrator (if necessary)")
+ self.__logger.info("Deploy orchestrator (if necessary)")
orchestrator_ready_time = time.time()
res_orchestrator = self.deploy_orchestrator()
# orchestrator is not mandatory
@@ -77,11 +77,11 @@ class VnfOnBoardingBase(base.TestCase):
self.details['orchestrator']['duration'] = round(
orchestrator_ready_time - self.start_time, 1)
except Exception:
- self.logger.warn("Problem with the Orchestrator", exc_info=True)
+ self.__logger.warn("Problem with the Orchestrator", exc_info=True)
# Deploy VNF
try:
- self.logger.info("Deploy VNF " + self.case_name)
+ self.__logger.info("Deploy VNF " + self.case_name)
res_deploy_vnf = self.deploy_vnf()
vnf_ready_time = time.time()
self.details['vnf']['status'] = res_deploy_vnf['status']
@@ -89,12 +89,12 @@ class VnfOnBoardingBase(base.TestCase):
self.details['vnf']['duration'] = round(
vnf_ready_time - orchestrator_ready_time, 1)
except Exception:
- self.logger.error("Error during VNF deployment", exc_info=True)
+ self.__logger.error("Error during VNF deployment", exc_info=True)
return base.TestCase.EX_TESTCASE_FAILED
# Test VNF
try:
- self.logger.info("Test VNF")
+ self.__logger.info("Test VNF")
res_test_vnf = self.test_vnf()
test_vnf_done_time = time.time()
self.details['test_vnf']['status'] = res_test_vnf['status']
@@ -102,7 +102,7 @@ class VnfOnBoardingBase(base.TestCase):
self.details['test_vnf']['duration'] = round(
test_vnf_done_time - vnf_ready_time, 1)
except Exception:
- self.logger.error("Error when running VNF tests", exc_info=True)
+ self.__logger.error("Error when running VNF tests", exc_info=True)
return base.TestCase.EX_TESTCASE_FAILED
# Clean the system
@@ -121,12 +121,13 @@ class VnfOnBoardingBase(base.TestCase):
self.creds = os_utils.get_credentials()
self.keystone_client = os_utils.get_keystone_client()
- self.logger.info("Prepare OpenStack plateform(create tenant and user)")
+ self.__logger.info(
+ "Prepare OpenStack plateform(create tenant and user)")
admin_user_id = os_utils.get_user_id(self.keystone_client,
self.creds['username'])
if not admin_user_id:
self.step_failure("Failed to get id of {0}".format(
- self.creds['username']))
+ self.creds['username']))
tenant_id = os_utils.get_tenant_id(self.keystone_client,
self.tenant_name)
@@ -136,7 +137,7 @@ class VnfOnBoardingBase(base.TestCase):
self.tenant_description)
if not tenant_id:
self.step_failure("Failed to get or create {0} tenant".format(
- self.tenant_name))
+ self.tenant_name))
roles_name = ["admin", "Admin"]
role_id = ''
for role_name in roles_name:
@@ -146,12 +147,12 @@ class VnfOnBoardingBase(base.TestCase):
if not role_id:
self.step_failure("Failed to get id for {0} role".format(
- role_name))
+ role_name))
if not os_utils.add_role_user(self.keystone_client, admin_user_id,
role_id, tenant_id):
self.step_failure("Failed to add {0} on tenant".format(
- self.creds['username']))
+ self.creds['username']))
user_id = os_utils.get_or_create_user(self.keystone_client,
self.tenant_name,
@@ -164,7 +165,7 @@ class VnfOnBoardingBase(base.TestCase):
os_utils.add_role_user(self.keystone_client, user_id,
role_id, tenant_id)
- self.logger.info("Update OpenStack creds informations")
+ self.__logger.info("Update OpenStack creds informations")
self.admin_creds = self.creds.copy()
self.admin_creds.update({
"tenant": self.tenant_name
@@ -183,21 +184,21 @@ class VnfOnBoardingBase(base.TestCase):
# TODO see how to use built-in exception from releng module
def deploy_vnf(self):
- self.logger.error("VNF must be deployed")
+ self.__logger.error("VNF must be deployed")
raise Exception("VNF not deployed")
def test_vnf(self):
- self.logger.error("VNF must be tested")
+ self.__logger.error("VNF must be tested")
raise Exception("VNF not tested")
# clean before openstack clean run
def clean(self):
- self.logger.info("test cleaning")
+ self.__logger.info("test cleaning")
def parse_results(self):
exit_code = self.EX_OK
self.result = "PASS"
- self.logger.info(self.details)
+ self.__logger.info(self.details)
# The 2 VNF steps must be OK to get a PASS result
if (self.details['vnf']['status'] is not "PASS" or
self.details['test_vnf']['status'] is not "PASS"):
@@ -213,7 +214,7 @@ class VnfOnBoardingBase(base.TestCase):
def step_failure(self, error_msg):
part = inspect.stack()[1][3]
- self.logger.error("Step {0} failed: {1}".format(part, error_msg))
+ self.__logger.error("Step {0} failed: {1}".format(part, error_msg))
try:
step_name = self.details_step_mapping[part]
part_info = self.details[step_name]
diff --git a/functest/energy/__init__.py b/functest/energy/__init__.py
new file mode 100644
index 000000000..e69de29bb
--- /dev/null
+++ b/functest/energy/__init__.py
diff --git a/functest/energy/energy.py b/functest/energy/energy.py
new file mode 100644
index 000000000..a20c79926
--- /dev/null
+++ b/functest/energy/energy.py
@@ -0,0 +1,203 @@
+#!/usr/bin/env python
+# -*- coding: UTF-8 -*-
+
+# Copyright (c) 2017 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
+
+"""This module manages calls to Energy recording API."""
+
+import json
+import logging
+import urllib
+import requests
+
+import functest.utils.functest_utils as ft_utils
+
+
+def enable_recording(method):
+ """
+ Decorator to record energy during "method" exection.
+
+ param method: Method to suround with start and stop
+ :type method: function
+
+ .. note:: "method" should belong to a class having a "case_name"
+ attribute
+ """
+ def wrapper(*args):
+ """Wrapper for decorator to handle method arguments."""
+ EnergyRecorder.start(args[0].case_name)
+ return_value = method(*args)
+ EnergyRecorder.stop()
+ return return_value
+ return wrapper
+
+
+# Class to manage energy recording sessions
+class EnergyRecorder(object):
+ """Manage Energy recording session."""
+
+ logger = logging.getLogger(__name__)
+ # Energy recording API connectivity settings
+ # see load_config method
+ energy_recorder_api = None
+
+ # Default initial step
+ INITIAL_STEP = "starting"
+
+ @staticmethod
+ def load_config():
+ """
+ Load connectivity settings from yaml.
+
+ Load connectivity settings to Energy recording API
+ Use functest global config yaml file
+ (see functest_utils.get_functest_config)
+ """
+ # Singleton pattern for energy_recorder_api static member
+ # Load only if not previouly done
+ if EnergyRecorder.energy_recorder_api is None:
+ environment = ft_utils.get_pod_name()
+
+ # API URL
+ energy_recorder_uri = ft_utils.get_functest_config(
+ "energy_recorder.api_url")
+ assert energy_recorder_uri
+ assert environment
+
+ energy_recorder_uri += "/recorders/environment/"
+ energy_recorder_uri += urllib.quote_plus(environment)
+ EnergyRecorder.logger.debug(
+ "API recorder at: " + energy_recorder_uri)
+
+ # Creds
+ user = ft_utils.get_functest_config(
+ "energy_recorder.api_user")
+ password = ft_utils.get_functest_config(
+ "energy_recorder.api_password")
+
+ if user != "" and password != "":
+ energy_recorder_api_auth = (user, password)
+ else:
+ energy_recorder_api_auth = None
+
+ # Final config
+ EnergyRecorder.energy_recorder_api = {
+ "uri": energy_recorder_uri,
+ "auth": energy_recorder_api_auth
+ }
+
+ @staticmethod
+ def start(scenario):
+ """
+ Start a recording session for scenario.
+
+ param scenario: Starting scenario
+ :type scenario: string
+ """
+ return_status = True
+ try:
+ EnergyRecorder.logger.debug("Starting recording")
+ # Ensure that connectyvity settings are loaded
+ EnergyRecorder.load_config()
+
+ # Create API payload
+ payload = {
+ "step": EnergyRecorder.INITIAL_STEP,
+ "scenario": scenario
+ }
+ # Call API to start energy recording
+ response = requests.post(
+ EnergyRecorder.energy_recorder_api["uri"],
+ data=json.dumps(payload),
+ auth=EnergyRecorder.energy_recorder_api["auth"],
+ headers={
+ 'content-type': 'application/json'
+ }
+ )
+ if response.status_code != 200:
+ log_msg = "Error while starting energy recording session\n{}"
+ log_msg = log_msg.format(response.text)
+ EnergyRecorder.logger.info(log_msg)
+ return_status = False
+
+ except Exception: # pylint: disable=broad-except
+ # Default exception handler to ensure that method
+ # is safe for caller
+ EnergyRecorder.logger.exception(
+ "Error while starting energy recorder API"
+ )
+ return_status = False
+ return return_status
+
+ @staticmethod
+ def stop():
+ """Stop current recording session."""
+ EnergyRecorder.logger.debug("Stopping recording")
+ return_status = True
+ try:
+ # Ensure that connectyvity settings are loaded
+ EnergyRecorder.load_config()
+
+ # Call API to stop energy recording
+ response = requests.delete(
+ EnergyRecorder.energy_recorder_api["uri"],
+ auth=EnergyRecorder.energy_recorder_api["auth"],
+ headers={
+ 'content-type': 'application/json'
+ }
+ )
+ if response.status_code != 200:
+ log_msg = "Error while stating energy recording session\n{}"
+ log_msg = log_msg.format(response.text)
+ EnergyRecorder.logger.error(log_msg)
+ return_status = False
+ except Exception: # pylint: disable=broad-except
+ # Default exception handler to ensure that method
+ # is safe for caller
+ EnergyRecorder.logger.exception(
+ "Error while stoping energy recorder API"
+ )
+ return_status = False
+ return return_status
+
+ @staticmethod
+ def set_step(step):
+ """Notify energy recording service of current step of the testcase."""
+ EnergyRecorder.logger.debug("Setting step")
+ return_status = True
+ try:
+ # Ensure that connectyvity settings are loaded
+ EnergyRecorder.load_config()
+
+ # Create API payload
+ payload = {
+ "step": step,
+ }
+
+ # Call API to define step
+ response = requests.post(
+ EnergyRecorder.energy_recorder_api["uri"] + "/step",
+ data=json.dumps(payload),
+ auth=EnergyRecorder.energy_recorder_api["auth"],
+ headers={
+ 'content-type': 'application/json'
+ }
+ )
+ if response.status_code != 200:
+ log_msg = "Error while setting current step of testcase\n{}"
+ log_msg = log_msg.format(response.text)
+ EnergyRecorder.logger.error(log_msg)
+ return_status = False
+ except Exception: # pylint: disable=broad-except
+ # Default exception handler to ensure that method
+ # is safe for caller
+ EnergyRecorder.logger.exception(
+ "Error while setting step on energy recorder API"
+ )
+ return_status = False
+ return return_status
diff --git a/functest/opnfv_tests/features/barometer.py b/functest/opnfv_tests/features/barometer.py
index 8a409406b..cbfe7d9a8 100644
--- a/functest/opnfv_tests/features/barometer.py
+++ b/functest/opnfv_tests/features/barometer.py
@@ -6,6 +6,8 @@
#
# http://www.apache.org/licenses/LICENSE-2.0
+import logging
+
from baro_tests import collectd
import functest.core.feature as base
@@ -16,5 +18,7 @@ class BarometerCollectd(base.Feature):
Class for executing barometercollectd testcase.
'''
+ __logger = logging.getLogger(__name__)
+
def execute(self):
- return collectd.main(self.logger)
+ return collectd.main(self.__logger)
diff --git a/functest/opnfv_tests/openstack/examples/create_instance_and_ip.py b/functest/opnfv_tests/openstack/examples/create_instance_and_ip.py
deleted file mode 100755
index b44008642..000000000
--- a/functest/opnfv_tests/openstack/examples/create_instance_and_ip.py
+++ /dev/null
@@ -1,128 +0,0 @@
-#!/usr/bin/python
-#
-# Copyright (c) 2015 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
-#
-# This script boots an instance and assigns a floating ip
-#
-
-import argparse
-import os
-import sys
-
-from functest.utils.constants import CONST
-import functest.utils.functest_logger as ft_logger
-import functest.utils.openstack_utils as os_utils
-
-parser = argparse.ArgumentParser()
-
-parser.add_argument("-r", "--report",
- help="Create json result file",
- action="store_true")
-
-args = parser.parse_args()
-
-""" logging configuration """
-logger = ft_logger.Logger("create_instance_and_ip").getLogger()
-
-HOME = CONST.dir_home + "/"
-
-VM_BOOT_TIMEOUT = 180
-
-EXAMPLE_INSTANCE_NAME = CONST.example_vm_name
-EXAMPLE_FLAVOR = CONST.example_flavor
-EXAMPLE_IMAGE_NAME = CONST.example_image_name
-IMAGE_FILENAME = CONST.openstack_image_file_name
-IMAGE_FORMAT = CONST.openstack_image_disk_format
-IMAGE_PATH = os.path.join(CONST.dir_functest_data, IMAGE_FILENAME)
-
-# NEUTRON Private Network parameters
-
-EXAMPLE_PRIVATE_NET_NAME = CONST.example_private_net_name
-EXAMPLE_PRIVATE_SUBNET_NAME = CONST.example_private_subnet_name
-EXAMPLE_PRIVATE_SUBNET_CIDR = CONST.example_private_subnet_cidr
-EXAMPLE_ROUTER_NAME = CONST.example_router_name
-
-EXAMPLE_SECGROUP_NAME = CONST.example_sg_name
-EXAMPLE_SECGROUP_DESCR = CONST.example_sg_desc
-
-
-def main():
-
- nova_client = os_utils.get_nova_client()
- neutron_client = os_utils.get_neutron_client()
- glance_client = os_utils.get_glance_client()
-
- image_id = os_utils.create_glance_image(glance_client,
- EXAMPLE_IMAGE_NAME,
- IMAGE_PATH,
- disk=IMAGE_FORMAT,
- container="bare",
- public=True)
-
- network_dic = os_utils.create_network_full(
- neutron_client,
- EXAMPLE_PRIVATE_NET_NAME,
- EXAMPLE_PRIVATE_SUBNET_NAME,
- EXAMPLE_ROUTER_NAME,
- EXAMPLE_PRIVATE_SUBNET_CIDR)
- if not network_dic:
- logger.error(
- "There has been a problem when creating the neutron network")
- sys.exit(-1)
-
- network_id = network_dic["net_id"]
-
- sg_id = os_utils.create_security_group_full(neutron_client,
- EXAMPLE_SECGROUP_NAME,
- EXAMPLE_SECGROUP_DESCR)
-
- # boot INTANCE
- logger.info("Creating instance '%s'..." % EXAMPLE_INSTANCE_NAME)
- logger.debug(
- "Configuration:\n name=%s \n flavor=%s \n image=%s \n "
- "network=%s \n"
- % (EXAMPLE_INSTANCE_NAME, EXAMPLE_FLAVOR, image_id, network_id))
- instance = os_utils.create_instance_and_wait_for_active(
- EXAMPLE_FLAVOR,
- image_id,
- network_id,
- EXAMPLE_INSTANCE_NAME)
-
- if instance is None:
- logger.error("Error while booting instance.")
- sys.exit(-1)
- # Retrieve IP of INSTANCE
- instance_ip = instance.networks.get(EXAMPLE_PRIVATE_NET_NAME)[0]
- logger.debug("Instance '%s' got private ip '%s'." %
- (EXAMPLE_INSTANCE_NAME, instance_ip))
-
- logger.info("Adding '%s' to security group '%s'..."
- % (EXAMPLE_INSTANCE_NAME, EXAMPLE_SECGROUP_NAME))
- os_utils.add_secgroup_to_instance(nova_client, instance.id, sg_id)
-
- logger.info("Creating floating IP for VM '%s'..." % EXAMPLE_INSTANCE_NAME)
- floatip_dic = os_utils.create_floating_ip(neutron_client)
- floatip = floatip_dic['fip_addr']
- # floatip_id = floatip_dic['fip_id']
-
- if floatip is None:
- logger.error("Cannot create floating IP.")
- sys.exit(-1)
- logger.info("Floating IP created: '%s'" % floatip)
-
- logger.info("Associating floating ip: '%s' to VM '%s' "
- % (floatip, EXAMPLE_INSTANCE_NAME))
- if not os_utils.add_floating_ip(nova_client, instance.id, floatip):
- logger.error("Cannot associate floating IP to VM.")
- sys.exit(-1)
-
- sys.exit(0)
-
-
-if __name__ == '__main__':
- main()
diff --git a/functest/opnfv_tests/openstack/rally/rally.py b/functest/opnfv_tests/openstack/rally/rally.py
index e07e2a8df..40f8386c8 100644
--- a/functest/opnfv_tests/openstack/rally/rally.py
+++ b/functest/opnfv_tests/openstack/rally/rally.py
@@ -8,7 +8,10 @@
# http://www.apache.org/licenses/LICENSE-2.0
#
+from __future__ import division
+
import json
+import logging
import os
import re
import subprocess
@@ -19,11 +22,9 @@ import yaml
from functest.core import testcase
from functest.utils.constants import CONST
-import functest.utils.functest_logger as ft_logger
-import functest.utils.functest_utils as ft_utils
import functest.utils.openstack_utils as os_utils
-logger = ft_logger.Logger('Rally').getLogger()
+logger = logging.getLogger(__name__)
class RallyBase(testcase.TestCase):
@@ -31,7 +32,7 @@ class RallyBase(testcase.TestCase):
'neutron', 'nova', 'quotas', 'requests', 'vm', 'all']
GLANCE_IMAGE_NAME = CONST.openstack_image_name
GLANCE_IMAGE_FILENAME = CONST.openstack_image_file_name
- GLANCE_IMAGE_PATH = os.path.join(CONST.dir_functest_data,
+ GLANCE_IMAGE_PATH = os.path.join(CONST.dir_functest_images,
GLANCE_IMAGE_FILENAME)
GLANCE_IMAGE_FORMAT = CONST.openstack_image_disk_format
FLAVOR_NAME = "m1.tiny"
@@ -480,11 +481,12 @@ class RallyBase(testcase.TestCase):
total_duration_str2 = "{0:<10}".format(total_duration_str)
total_nb_tests_str = "{0:<13}".format(total_nb_tests)
- if len(self.summary):
- success_rate = total_success / len(self.summary)
- else:
- success_rate = 100
- success_rate = "{:0.2f}".format(success_rate)
+ try:
+ self.result = total_success / len(self.summary)
+ except ZeroDivisionError:
+ self.result = 100
+
+ success_rate = "{:0.2f}".format(self.result)
success_rate_str = "{0:<10}".format(str(success_rate) + '%')
report += ("+===================+============"
"+===============+===========+")
@@ -500,12 +502,10 @@ class RallyBase(testcase.TestCase):
'nb tests': total_nb_tests,
'nb success': success_rate}})
- self.result = ft_utils.check_success_rate(
- self.case_name, success_rate)
self.details = payload
- logger.info("Rally '%s' success_rate is %s%%, is marked as %s"
- % (self.case_name, success_rate, self.result))
+ logger.info("Rally '%s' success_rate is %s%%"
+ % (self.case_name, success_rate))
def _clean_up(self):
if self.volume_type:
diff --git a/functest/opnfv_tests/openstack/refstack_client/defcore.txt b/functest/opnfv_tests/openstack/refstack_client/defcore.txt
index be8fd8998..0a1787ef3 100644
--- a/functest/opnfv_tests/openstack/refstack_client/defcore.txt
+++ b/functest/opnfv_tests/openstack/refstack_client/defcore.txt
@@ -1,4 +1,11 @@
-# Set of DefCore tempest test cases not flagged and required. It only contains OpenStack core (no object storage)
+# Set of DefCore tempest test cases not flagged and required.
+# According to https://github.com/openstack/interop/blob/master/2016.08/procedure.rst,
+# some tests are still flagged due to outstanding bugs in the Tempest library,
+# particularly tests that require SSH. Refstack developers
+# are working on correcting these bugs upstream. Please note that although some tests
+# are flagged because of bugs, there is still an expectation that the capabilities
+# covered by the tests are available.
+# It only contains Openstack core compute (no object storage)
# The approved guidelines (2016.08) are valid for Kilo, Liberty, Mitaka and Newton releases of OpenStack
# The list can be generated using the Rest API from RefStack project:
# https://refstack.openstack.org/api/v1/guidelines/2016.08/tests?target=compute&type=required&alias=true&flag=false
diff --git a/functest/opnfv_tests/openstack/refstack_client/refstack_client.py b/functest/opnfv_tests/openstack/refstack_client/refstack_client.py
index 2f2fc00f7..2a2718dd8 100755
--- a/functest/opnfv_tests/openstack/refstack_client/refstack_client.py
+++ b/functest/opnfv_tests/openstack/refstack_client/refstack_client.py
@@ -5,7 +5,12 @@
# 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
+
+from __future__ import division
+
+
import argparse
+import logging
import os
import re
import sys
@@ -15,12 +20,11 @@ import time
from functest.core import testcase
from functest.opnfv_tests.openstack.tempest import conf_utils
from functest.utils.constants import CONST
-import functest.utils.functest_logger as ft_logger
import functest.utils.functest_utils as ft_utils
from tempest_conf import TempestConf
""" logging configuration """
-logger = ft_logger.Logger("refstack_defcore").getLogger()
+logger = logging.getLogger(__name__)
class RefstackClient(testcase.TestCase):
@@ -123,7 +127,11 @@ class RefstackClient(testcase.TestCase):
skipped_testcases += match + ", "
num_executed = int(num_tests) - int(num_skipped)
- success_rate = 100 * int(num_success) / int(num_executed)
+
+ try:
+ self.result = 100 * int(num_success) / int(num_executed)
+ except ZeroDivisionError:
+ logger.error("No test has been executed")
self.details = {"tests": int(num_tests),
"failures": int(num_failures),
@@ -131,12 +139,10 @@ class RefstackClient(testcase.TestCase):
"errors": failed_testcases,
"skipped": skipped_testcases}
except Exception:
- success_rate = 0
+ self.result = 0
- self.result = ft_utils.check_success_rate(
- self.case_name, success_rate)
- logger.info("Testcase %s success_rate is %s%%, is marked as %s"
- % (self.case_name, success_rate, self.result))
+ logger.info("Testcase %s success_rate is %s%%"
+ % (self.case_name, self.result))
def run(self):
'''used for functest command line,
@@ -220,6 +226,7 @@ class RefstackClientParser(object):
if __name__ == '__main__':
+ logging.basicConfig()
refstackclient = RefstackClient()
parser = RefstackClientParser()
args = parser.parse_args(sys.argv[1:])
diff --git a/functest/opnfv_tests/openstack/refstack_client/tempest_conf.py b/functest/opnfv_tests/openstack/refstack_client/tempest_conf.py
index d01f08727..5c04253c3 100755
--- a/functest/opnfv_tests/openstack/refstack_client/tempest_conf.py
+++ b/functest/opnfv_tests/openstack/refstack_client/tempest_conf.py
@@ -5,15 +5,15 @@
# 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 logging
import os
from functest.opnfv_tests.openstack.tempest import conf_utils
from functest.utils import openstack_utils
from functest.utils.constants import CONST
-import functest.utils.functest_logger as ft_logger
""" logging configuration """
-logger = ft_logger.Logger("refstack_defcore").getLogger()
+logger = logging.getLogger(__name__)
class TempestConf(object):
@@ -48,5 +48,6 @@ class TempestConf(object):
if __name__ == '__main__':
+ logging.basicConfig()
tempestconf = TempestConf()
tempestconf.main()
diff --git a/functest/opnfv_tests/openstack/snaps/health_check.py b/functest/opnfv_tests/openstack/snaps/health_check.py
index c057eb2b0..0daddcdd2 100644
--- a/functest/opnfv_tests/openstack/snaps/health_check.py
+++ b/functest/opnfv_tests/openstack/snaps/health_check.py
@@ -23,14 +23,15 @@ class HealthCheck(SnapsTestRunner):
"""
def __init__(self, **kwargs):
if "case_name" not in kwargs:
- kwargs["case_name"] = "snaps_health_check"
+ kwargs["case_name"] = "snaps_images_cirros"
super(HealthCheck, self).__init__(**kwargs)
self.suite = unittest.TestSuite()
image_custom_config = None
- if hasattr(CONST, 'snaps_health_check'):
- image_custom_config = CONST.__getattribute__('snaps_health_check')
+
+ if hasattr(CONST, 'snaps_images_cirros'):
+ image_custom_config = CONST.__getattribute__('snaps_images_cirros')
self.suite.addTest(
OSIntegrationTestCase.parameterize(
SimpleHealthCheck, os_creds=self.os_creds,
diff --git a/functest/opnfv_tests/openstack/snaps/smoke.py b/functest/opnfv_tests/openstack/snaps/smoke.py
index 2c6fc2553..d9f95e90c 100644
--- a/functest/opnfv_tests/openstack/snaps/smoke.py
+++ b/functest/opnfv_tests/openstack/snaps/smoke.py
@@ -28,11 +28,9 @@ class SnapsSmoke(SnapsTestRunner):
self.suite = unittest.TestSuite()
- # The snaps smoke test uses the same config as the
- # snaps_health_check suite, so reuse it here
- image_custom_config = None
- if hasattr(CONST, 'snaps_health_check'):
- image_custom_config = CONST.__getattribute__('snaps_health_check')
+ image_config = None
+ if hasattr(CONST, 'snaps_images_cirros'):
+ image_config = CONST.__getattribute__('snaps_images_cirros')
# Tests requiring floating IPs leverage files contained within the
# SNAPS repository and are found relative to that path
@@ -47,5 +45,5 @@ class SnapsSmoke(SnapsTestRunner):
ext_net_name=self.ext_net_name,
use_keystone=self.use_keystone,
flavor_metadata=self.flavor_metadata,
- image_metadata=image_custom_config,
+ image_metadata=image_config,
use_floating_ips=self.use_fip)
diff --git a/functest/opnfv_tests/openstack/snaps/snaps_test_runner.py b/functest/opnfv_tests/openstack/snaps/snaps_test_runner.py
index 8a68cad9e..94b97551a 100644
--- a/functest/opnfv_tests/openstack/snaps/snaps_test_runner.py
+++ b/functest/opnfv_tests/openstack/snaps/snaps_test_runner.py
@@ -5,6 +5,8 @@
#
# http://www.apache.org/licenses/LICENSE-2.0
+import logging
+
from functest.core.pytest_suite_runner import PyTestSuiteRunner
from functest.opnfv_tests.openstack.snaps import snaps_utils
from functest.utils import functest_utils
@@ -16,12 +18,11 @@ from snaps.openstack.tests import openstack_tests
class SnapsTestRunner(PyTestSuiteRunner):
"""
- This test executes the SNAPS Python Test case SimpleHealthCheck which
- creates a VM with a single port with an IPv4 address that is assigned by
- DHCP. This test then validates the expected IP with the actual
+ This test executes the SNAPS Python Tests
"""
def __init__(self, **kwargs):
super(SnapsTestRunner, self).__init__(**kwargs)
+ self.logger = logging.getLogger(__name__)
self.os_creds = openstack_tests.get_credentials(
os_env_file=CONST.__getattribute__('openstack_creds'),
diff --git a/functest/opnfv_tests/openstack/tempest/conf_utils.py b/functest/opnfv_tests/openstack/tempest/conf_utils.py
index f4a94f654..cd6a2a8c1 100644
--- a/functest/opnfv_tests/openstack/tempest/conf_utils.py
+++ b/functest/opnfv_tests/openstack/tempest/conf_utils.py
@@ -8,13 +8,13 @@
# http://www.apache.org/licenses/LICENSE-2.0
#
import ConfigParser
+import logging
import os
import re
import shutil
import subprocess
from functest.utils.constants import CONST
-import functest.utils.functest_logger as ft_logger
import functest.utils.functest_utils as ft_utils
import functest.utils.openstack_utils as os_utils
@@ -22,7 +22,7 @@ import functest.utils.openstack_utils as os_utils
IMAGE_ID_ALT = None
FLAVOR_ID_ALT = None
REPO_PATH = CONST.dir_repo_functest
-GLANCE_IMAGE_PATH = os.path.join(CONST.dir_functest_data,
+GLANCE_IMAGE_PATH = os.path.join(CONST.dir_functest_images,
CONST.openstack_image_file_name)
TEMPEST_TEST_LIST_DIR = CONST.dir_tempest_cases
TEMPEST_RESULTS_DIR = os.path.join(CONST.dir_results,
@@ -42,7 +42,7 @@ CI_INSTALLER_TYPE = CONST.INSTALLER_TYPE
CI_INSTALLER_IP = CONST.INSTALLER_IP
""" logging configuration """
-logger = ft_logger.Logger("Tempest").getLogger()
+logger = logging.getLogger(__name__)
def create_tempest_resources(use_custom_images=False,
@@ -279,12 +279,20 @@ def configure_tempest_update_params(tempest_conf_file,
config.set('identity', 'tenant_name', CONST.tempest_identity_tenant_name)
config.set('identity', 'username', CONST.tempest_identity_user_name)
config.set('identity', 'password', CONST.tempest_identity_user_password)
+ config.set('identity', 'region', 'RegionOne')
config.set(
'validation', 'ssh_timeout', CONST.tempest_validation_ssh_timeout)
config.set('object-storage', 'operator_role',
CONST.tempest_object_storage_operator_role)
if CONST.OS_ENDPOINT_TYPE is not None:
+ sections = config.sections()
+ if os_utils.is_keystone_v3():
+ config.set('identity', 'v3_endpoint_type', CONST.OS_ENDPOINT_TYPE)
+ if 'identity-feature-enabled' not in sections:
+ config.add_section('identity-feature-enabled')
+ config.set('identity-feature-enabled', 'api_v2', False)
+ config.set('identity-feature-enabled', 'api_v2_admin', False)
services_list = ['compute',
'volume',
'image',
@@ -292,7 +300,6 @@ def configure_tempest_update_params(tempest_conf_file,
'data-processing',
'object-storage',
'orchestration']
- sections = config.sections()
for service in services_list:
if service not in sections:
config.add_section(service)
diff --git a/functest/opnfv_tests/openstack/tempest/tempest.py b/functest/opnfv_tests/openstack/tempest/tempest.py
index e6c6b44f7..a41d07c7e 100644
--- a/functest/opnfv_tests/openstack/tempest/tempest.py
+++ b/functest/opnfv_tests/openstack/tempest/tempest.py
@@ -8,6 +8,9 @@
# http://www.apache.org/licenses/LICENSE-2.0
#
+from __future__ import division
+
+import logging
import os
import re
import shutil
@@ -19,11 +22,10 @@ import yaml
from functest.core import testcase
from functest.opnfv_tests.openstack.tempest import conf_utils
from functest.utils.constants import CONST
-import functest.utils.functest_logger as ft_logger
import functest.utils.functest_utils as ft_utils
""" logging configuration """
-logger = ft_logger.Logger("Tempest").getLogger()
+logger = logging.getLogger(__name__)
class TempestCommon(testcase.TestCase):
@@ -181,7 +183,13 @@ class TempestCommon(testcase.TestCase):
try:
num_executed = int(num_tests) - int(num_skipped)
- success_rate = 100 * int(num_success) / int(num_executed)
+ try:
+ self.result = 100 * int(num_success) / int(num_executed)
+ except ZeroDivisionError:
+ logger.error("No test has been executed")
+ self.result = 0
+ return
+
with open(os.path.join(conf_utils.TEMPEST_RESULTS_DIR,
"tempest.log"), 'r') as logfile:
output = logfile.read()
@@ -198,12 +206,10 @@ class TempestCommon(testcase.TestCase):
"errors": error_logs,
"skipped": skipped_testcase}
except Exception:
- success_rate = 0
+ self.result = 0
- self.result = ft_utils.check_success_rate(
- self.case_name, success_rate)
- logger.info("Tempest %s success_rate is %s%%, is marked as %s"
- % (self.case_name, success_rate, self.result))
+ logger.info("Tempest %s success_rate is %s%%"
+ % (self.case_name, self.result))
def run(self):
diff --git a/functest/opnfv_tests/openstack/vping/vping_base.py b/functest/opnfv_tests/openstack/vping/vping_base.py
index 8bf263eb2..8e71bf82c 100644
--- a/functest/opnfv_tests/openstack/vping/vping_base.py
+++ b/functest/opnfv_tests/openstack/vping/vping_base.py
@@ -7,281 +7,194 @@
#
# http://www.apache.org/licenses/LICENSE-2.0
+from datetime import datetime
+import logging
import os
-import pprint
import time
-from datetime import datetime
+import uuid
-import functest.core.testcase as testcase
-import functest.utils.openstack_utils as os_utils
+from functest.core.testcase import TestCase
+from functest.utils import functest_utils
from functest.utils.constants import CONST
+from snaps.openstack import create_flavor
+from snaps.openstack.create_flavor import FlavorSettings, OpenStackFlavor
+from snaps.openstack.create_network import NetworkSettings, SubnetSettings
+from snaps.openstack.tests import openstack_tests
+from snaps.openstack.utils import deploy_utils, nova_utils
+
+
+class VPingBase(TestCase):
+
+ """
+ Base class for vPing tests that check connectivity between two VMs shared
+ internal network.
+ This class is responsible for creating the image, internal network.
+ """
-class VPingBase(testcase.TestCase):
def __init__(self, **kwargs):
super(VPingBase, self).__init__(**kwargs)
- self.logger = None
- self.functest_repo = CONST.dir_repo_functest
- self.repo = CONST.dir_vping
- self.vm1_name = CONST.vping_vm_name_1
- self.vm2_name = CONST.vping_vm_name_2
- self.vm_boot_timeout = 180
- self.vm_delete_timeout = 100
- self.ping_timeout = CONST.vping_ping_timeout
-
- self.image_name = CONST.vping_image_name
- self.image_filename = CONST.openstack_image_file_name
- self.image_format = CONST.openstack_image_disk_format
- self.image_username = CONST.openstack_image_username
- self.image_password = CONST.openstack_image_password
- self.image_path = os.path.join(CONST.dir_functest_data,
- self.image_filename)
-
- self.flavor_name = CONST.vping_vm_flavor
+
+ self.logger = logging.getLogger(self.__class__.__name__)
+
+ self.functest_repo = CONST.__getattribute__('dir_repo_functest')
+ self.guid = ''
+ if CONST.__getattribute__('vping_unique_names'):
+ self.guid = '-' + str(uuid.uuid4())
+
+ self.os_creds = openstack_tests.get_credentials(
+ os_env_file=CONST.__getattribute__('openstack_creds'))
+
+ self.repo = CONST.__getattribute__('dir_vping')
+
+ self.creators = list()
+ self.image_creator = None
+ self.network_creator = None
+ self.vm1_creator = None
+ self.vm2_creator = None
+
+ self.self_cleanup = CONST.__getattribute__('vping_cleanup_objects')
+
+ # Image constants
+ self.image_name =\
+ CONST.__getattribute__('vping_image_name') + self.guid
+
+ # VM constants
+ self.vm1_name = CONST.__getattribute__('vping_vm_name_1') + self.guid
+ self.vm2_name = CONST.__getattribute__('vping_vm_name_2') + self.guid
+ self.vm_boot_timeout = CONST.__getattribute__('vping_vm_boot_timeout')
+ self.vm_delete_timeout =\
+ CONST.__getattribute__('vping_vm_delete_timeout')
+ self.vm_ssh_connect_timeout = CONST.vping_vm_ssh_connect_timeout
+ self.ping_timeout = CONST.__getattribute__('vping_ping_timeout')
+ self.flavor_name = 'vping-flavor' + self.guid
# NEUTRON Private Network parameters
- self.private_net_name = CONST.vping_private_net_name
- self.private_subnet_name = CONST.vping_private_subnet_name
- self.private_subnet_cidr = CONST.vping_private_subnet_cidr
- self.router_name = CONST.vping_router_name
- self.sg_name = CONST.vping_sg_name
- self.sg_desc = CONST.vping_sg_desc
- self.neutron_client = os_utils.get_neutron_client()
- self.glance_client = os_utils.get_glance_client()
- self.nova_client = os_utils.get_nova_client()
-
- def run(self, **kwargs):
- if not self.check_repo_exist():
- return testcase.TestCase.EX_RUN_ERROR
-
- image_id = self.create_image()
- if not image_id:
- return testcase.TestCase.EX_RUN_ERROR
-
- flavor = self.get_flavor()
- if not flavor:
- return testcase.TestCase.EX_RUN_ERROR
-
- network_id = self.create_network_full()
- if not network_id:
- return testcase.TestCase.EX_RUN_ERROR
-
- sg_id = self.create_security_group()
- if not sg_id:
- return testcase.TestCase.EX_RUN_ERROR
-
- self.delete_exist_vms()
+ self.private_net_name =\
+ CONST.__getattribute__('vping_private_net_name') + self.guid
+ self.private_subnet_name =\
+ CONST.__getattribute__('vping_private_subnet_name') + self.guid
+ self.private_subnet_cidr =\
+ CONST.__getattribute__('vping_private_subnet_cidr')
- self.start_time = time.time()
- self.logger.info("vPing Start Time:'%s'" % (
- datetime.fromtimestamp(self.start_time).strftime(
- '%Y-%m-%d %H:%M:%S')))
+ scenario = functest_utils.get_scenario()
- vm1 = self.boot_vm(self.vm1_name,
- image_id,
- flavor,
- network_id,
- None,
- sg_id)
- if not vm1:
- return testcase.TestCase.EX_RUN_ERROR
-
- test_ip = self.get_test_ip(vm1)
- vm2 = self.boot_vm(self.vm2_name,
- image_id,
- flavor,
- network_id,
- test_ip,
- sg_id)
- if not vm2:
- return testcase.TestCase.EX_RUN_ERROR
-
- EXIT_CODE = self.do_vping(vm2, test_ip)
- if EXIT_CODE == testcase.TestCase.EX_RUN_ERROR:
- return EXIT_CODE
+ self.flavor_metadata = create_flavor.MEM_PAGE_SIZE_ANY
+ if 'ovs' in scenario or 'fdio' in scenario:
+ self.flavor_metadata = create_flavor.MEM_PAGE_SIZE_LARGE
- self.stop_time = time.time()
- self.parse_result(EXIT_CODE,
- self.start_time,
- self.stop_time)
- return testcase.TestCase.EX_OK
+ self.cirros_image_config = None
- def boot_vm_preparation(self, config, vmname, test_ip):
- pass
+ # Move this configuration option up for all tests to leverage
+ if hasattr(CONST, 'snaps_images_cirros'):
+ self.cirros_image_config = CONST.__getattribute__(
+ 'snaps_images_cirros')
- def do_vping(self, vm, test_ip):
- raise NotImplementedError('vping execution is not implemented')
+ def run(self):
+ """
+ Begins the test execution which should originate from the subclass
+ """
- def check_repo_exist(self):
if not os.path.exists(self.functest_repo):
- self.logger.error("Functest repository not found '%s'"
- % self.functest_repo)
- return False
- return True
+ raise Exception(
+ "Functest repository not found '%s'" % self.functest_repo)
- def create_image(self):
- _, image_id = os_utils.get_or_create_image(self.image_name,
- self.image_path,
- self.image_format)
- if not image_id:
- return None
+ self.logger.info('Begin virtual environment setup')
- return image_id
+ self.start_time = time.time()
+ self.logger.info("vPing Start Time:'%s'" % (
+ datetime.fromtimestamp(self.start_time).strftime(
+ '%Y-%m-%d %H:%M:%S')))
- def get_flavor(self):
- try:
- flavor = self.nova_client.flavors.find(name=self.flavor_name)
- self.logger.info("Using existing Flavor '%s'..."
- % self.flavor_name)
- return flavor
- except:
- self.logger.error("Flavor '%s' not found." % self.flavor_name)
- self.logger.info("Available flavors are: ")
- self.pMsg(self.nova_client.flavor.list())
- return None
-
- def create_network_full(self):
- network_dic = os_utils.create_network_full(self.neutron_client,
- self.private_net_name,
- self.private_subnet_name,
- self.router_name,
- self.private_subnet_cidr)
-
- if not network_dic:
- self.logger.error(
- "There has been a problem when creating the neutron network")
- return None
- network_id = network_dic["net_id"]
- return network_id
-
- def create_security_group(self):
- sg_id = os_utils.get_security_group_id(self.neutron_client,
- self.sg_name)
- if sg_id != '':
- self.logger.info("Using existing security group '%s'..."
- % self.sg_name)
+ self.__delete_exist_vms()
+
+ image_base_name = self.image_name + '-' + str(self.guid)
+ os_image_settings = openstack_tests.cirros_image_settings(
+ image_base_name, image_metadata=self.cirros_image_config)
+ self.logger.info("Creating image with name: '%s'" % self.image_name)
+
+ self.image_creator = deploy_utils.create_image(
+ self.os_creds, os_image_settings)
+ self.creators.append(self.image_creator)
+
+ self.logger.info(
+ "Creating network with name: '%s'" % self.private_net_name)
+ self.network_creator = deploy_utils.create_network(
+ self.os_creds,
+ NetworkSettings(name=self.private_net_name,
+ subnet_settings=[SubnetSettings(
+ name=self.private_subnet_name,
+ cidr=self.private_subnet_cidr)]))
+ self.creators.append(self.network_creator)
+
+ self.logger.info(
+ "Creating flavor with name: '%s'" % self.flavor_name)
+ flavor_creator = OpenStackFlavor(
+ self.os_creds,
+ FlavorSettings(name=self.flavor_name, ram=512, disk=1, vcpus=1,
+ metadata=self.flavor_metadata))
+ flavor_creator.create()
+ self.creators.append(flavor_creator)
+
+ def _execute(self):
+ """
+ Method called by subclasses after environment has been setup
+ :return: the exit code
+ """
+ self.logger.info('Begin test execution')
+
+ test_ip = self.vm1_creator.get_port_ip(
+ self.vm1_creator.instance_settings.port_settings[0].name)
+
+ if self.vm1_creator.vm_active(
+ block=True) and self.vm2_creator.vm_active(block=True):
+ result = self._do_vping(self.vm2_creator, test_ip)
else:
- self.logger.info("Creating security group '%s'..."
- % self.sg_name)
- SECGROUP = os_utils.create_security_group(self.neutron_client,
- self.sg_name,
- self.sg_desc)
- if not SECGROUP:
- self.logger.error("Failed to create the security group...")
- return None
-
- sg_id = SECGROUP['id']
-
- self.logger.debug("Security group '%s' with ID=%s created "
- "successfully." % (SECGROUP['name'], sg_id))
-
- self.logger.debug("Adding ICMP rules in security group '%s'..."
- % self.sg_name)
- if not os_utils.create_secgroup_rule(self.neutron_client, sg_id,
- 'ingress', 'icmp'):
- self.logger.error("Failed to create security group rule...")
- return None
-
- self.logger.debug("Adding SSH rules in security group '%s'..."
- % self.sg_name)
- if not os_utils.create_secgroup_rule(self.neutron_client, sg_id,
- 'ingress', 'tcp',
- '22', '22'):
- self.logger.error("Failed to create security group rule...")
- return None
-
- if not os_utils.create_secgroup_rule(
- self.neutron_client, sg_id, 'egress', 'tcp', '22', '22'):
- self.logger.error("Failed to create security group rule...")
- return None
- return sg_id
-
- def delete_exist_vms(self):
- servers = self.nova_client.servers.list()
+ raise Exception('VMs never became active')
+
+ if result == TestCase.EX_RUN_ERROR:
+ return TestCase.EX_RUN_ERROR
+
+ self.stop_time = time.time()
+ self.result = 100
+ return TestCase.EX_OK
+
+ def _cleanup(self):
+ """
+ Cleanup all OpenStack objects. Should be called on completion
+ :return:
+ """
+ if self.self_cleanup:
+ for creator in reversed(self.creators):
+ try:
+ creator.clean()
+ except Exception as e:
+ self.logger.error('Unexpected error cleaning - %s', e)
+
+ def _do_vping(self, vm_creator, test_ip):
+ """
+ Method to be implemented by subclasses
+ Begins the real test after the OpenStack environment has been setup
+ :param vm_creator: the SNAPS VM instance creator object
+ :param test_ip: the IP to which the VM needs to issue the ping
+ :return: T/F
+ """
+ raise NotImplementedError('vping execution is not implemented')
+
+ def __delete_exist_vms(self):
+ """
+ Cleans any existing VMs using the same name.
+ """
+ nova_client = nova_utils.nova_client(self.os_creds)
+ servers = nova_client.servers.list()
for server in servers:
if server.name == self.vm1_name or server.name == self.vm2_name:
self.logger.info("Deleting instance %s..." % server.name)
server.delete()
- def boot_vm(self, vmname, image_id, flavor, network_id, test_ip, sg_id):
- config = dict()
- config['name'] = vmname
- config['flavor'] = flavor
- config['image'] = image_id
- config['nics'] = [{"net-id": network_id}]
- self.boot_vm_preparation(config, vmname, test_ip)
- self.logger.info("Creating instance '%s'..." % vmname)
- self.logger.debug("Configuration: %s" % config)
- vm = self.nova_client.servers.create(**config)
-
- # wait until VM status is active
- if not self.waitVmActive(self.nova_client, vm):
- vm_status = os_utils.get_instance_status(self.nova_client, vm)
- self.logger.error("Instance '%s' cannot be booted. Status is '%s'"
- % (vmname, vm_status))
- return None
- else:
- self.logger.info("Instance '%s' is ACTIVE." % vmname)
-
- self.add_secgroup(vmname, vm.id, sg_id)
-
- return vm
-
- def waitVmActive(self, nova, vm):
- # sleep and wait for VM status change
- sleep_time = 3
- count = self.vm_boot_timeout / sleep_time
- while True:
- status = os_utils.get_instance_status(nova, vm)
- self.logger.debug("Status: %s" % status)
- if status == "ACTIVE":
- return True
- if status == "ERROR" or status == "error":
- return False
- if count == 0:
- self.logger.debug("Booting a VM timed out...")
- return False
- count -= 1
- time.sleep(sleep_time)
- return False
-
- def add_secgroup(self, vmname, vm_id, sg_id):
- self.logger.info("Adding '%s' to security group '%s'..." %
- (vmname, self.sg_name))
- os_utils.add_secgroup_to_instance(self.nova_client, vm_id, sg_id)
-
- def get_test_ip(self, vm):
- test_ip = vm.networks.get(self.private_net_name)[0]
- self.logger.debug("Instance '%s' got %s" % (vm.name, test_ip))
- return test_ip
-
- def parse_result(self, code, start_time, stop_time):
- test_status = "FAIL"
- if code == 0:
- self.logger.info("vPing OK")
- duration = round(stop_time - start_time, 1)
- self.logger.info("vPing duration:'%s'" % duration)
- test_status = "PASS"
- elif code == -2:
- duration = 0
- self.logger.info("Userdata is not supported in nova boot. "
- "Aborting test...")
- else:
- duration = 0
- self.logger.error("vPing FAILED")
-
- self.details = {'timestart': start_time,
- 'duration': duration,
- 'status': test_status}
- self.result = test_status
-
- @staticmethod
- def pMsg(msg):
- """pretty printing"""
- pprint.PrettyPrinter(indent=4).pprint(msg)
-
class VPingMain(object):
+
def __init__(self, vping_cls):
self.vping = vping_cls()
@@ -291,6 +204,6 @@ class VPingMain(object):
if result != VPingBase.EX_OK:
return result
if kwargs['report']:
- return self.vping.push_to_db()
- except Exception:
+ return self.vping.publish_report()
+ except:
return VPingBase.EX_RUN_ERROR
diff --git a/functest/opnfv_tests/openstack/vping/vping_ssh.py b/functest/opnfv_tests/openstack/vping/vping_ssh.py
index c26c4e0c0..0ad77402e 100755
--- a/functest/opnfv_tests/openstack/vping/vping_ssh.py
+++ b/functest/opnfv_tests/openstack/vping/vping_ssh.py
@@ -7,124 +7,161 @@
#
# http://www.apache.org/licenses/LICENSE-2.0
+import argparse
import os
-import re
+from scp import SCPClient
import sys
import time
-import argparse
-import paramiko
-from scp import SCPClient
-
-import functest.utils.functest_logger as ft_logger
-import functest.utils.openstack_utils as os_utils
+from snaps.openstack.create_instance import FloatingIpSettings, \
+ VmInstanceSettings
+from snaps.openstack.create_keypairs import KeypairSettings
+from snaps.openstack.create_network import PortSettings
+from snaps.openstack.create_router import RouterSettings
+from snaps.openstack.create_security_group import Direction, Protocol, \
+ SecurityGroupSettings, SecurityGroupRuleSettings
+from snaps.openstack.utils import deploy_utils
+
+from functest.core.testcase import TestCase
+from functest.opnfv_tests.openstack.snaps import snaps_utils
+from functest.utils.constants import CONST
import vping_base
-import functest.core.testcase as testcase
class VPingSSH(vping_base.VPingBase):
+ """
+ Class to execute the vPing test using a Floating IP to connect to one VM
+ to issue the ping command to the second
+ """
def __init__(self, **kwargs):
if "case_name" not in kwargs:
kwargs["case_name"] = "vping_ssh"
super(VPingSSH, self).__init__(**kwargs)
- self.logger = ft_logger.Logger(self.case_name).getLogger()
-
- def do_vping(self, vm, test_ip):
- floatip = self.add_float_ip(vm)
- if not floatip:
- return testcase.TestCase.EX_RUN_ERROR
- ssh = self.establish_ssh(vm, floatip)
- if not ssh:
- return testcase.TestCase.EX_RUN_ERROR
- if not self.transfer_ping_script(ssh, floatip):
- return testcase.TestCase.EX_RUN_ERROR
- return self.do_vping_ssh(ssh, test_ip)
-
- def add_float_ip(self, vm):
- self.logger.info("Creating floating IP for VM '%s'..." % self.vm2_name)
- floatip_dic = os_utils.create_floating_ip(self.neutron_client)
- floatip = floatip_dic['fip_addr']
-
- if floatip is None:
- self.logger.error("Cannot create floating IP.")
- return None
- self.logger.info("Floating IP created: '%s'" % floatip)
-
- self.logger.info("Associating floating ip: '%s' to VM '%s' "
- % (floatip, self.vm2_name))
- if not os_utils.add_floating_ip(self.nova_client, vm.id, floatip):
- self.logger.error("Cannot associate floating IP to VM.")
- return None
-
- return floatip
-
- def establish_ssh(self, vm, floatip):
- self.logger.info("Trying to establish SSH connection to %s..."
- % floatip)
- ssh = paramiko.SSHClient()
- ssh.set_missing_host_key_policy(paramiko.AutoAddPolicy())
-
- timeout = 50
- nolease = False
- got_ip = False
- discover_count = 0
- cidr_first_octet = self.private_subnet_cidr.split('.')[0]
- while timeout > 0:
- try:
- ssh.connect(floatip, username=self.image_username,
- password=self.image_password, timeout=2)
- self.logger.debug("SSH connection established to %s."
- % floatip)
- break
- except:
- self.logger.debug("Waiting for %s..." % floatip)
- time.sleep(6)
- timeout -= 1
-
- console_log = vm.get_console_output()
-
- # print each "Sending discover" captured on the console log
- if (len(re.findall("Sending discover", console_log)) >
- discover_count and not got_ip):
- discover_count += 1
- self.logger.debug("Console-log '%s': Sending discover..."
- % self.vm2_name)
-
- # check if eth0 got an ip,the line looks like this:
- # "inet addr:192.168."....
- # if the dhcp agent fails to assing ip, this line will not appear
- if "inet addr:" + cidr_first_octet in console_log and not got_ip:
- got_ip = True
- self.logger.debug("The instance '%s' succeeded to get the IP "
- "from the dhcp agent." % self.vm2_name)
-
- # if dhcp not work,it shows "No lease, failing".The test will fail
- if ("No lease, failing" in console_log and
- not nolease and
- not got_ip):
- nolease = True
- self.logger.debug("Console-log '%s': No lease, failing..."
- % self.vm2_name)
- self.logger.info("The instance failed to get an IP from DHCP "
- "agent. The test will probably timeout...")
-
- if timeout == 0: # 300 sec timeout (5 min)
- self.logger.error("Cannot establish connection to IP '%s'. "
- "Aborting" % floatip)
- return None
- return ssh
-
- def transfer_ping_script(self, ssh, floatip):
- self.logger.info("Trying to transfer ping.sh to %s..." % floatip)
+
+ self.kp_name = CONST.__getattribute__('vping_keypair_name') + self.guid
+ self.kp_priv_file = CONST.__getattribute__('vping_keypair_priv_file')
+ self.kp_pub_file = CONST.__getattribute__('vping_keypair_pub_file')
+ self.router_name =\
+ CONST.__getattribute__('vping_router_name') + self.guid
+ self.sg_name = CONST.__getattribute__('vping_sg_name') + self.guid
+ self.sg_desc = CONST.__getattribute__('vping_sg_desc')
+
+ self.ext_net_name = snaps_utils.get_ext_net_name(self.os_creds)
+
+ def run(self):
+ """
+ Sets up the OpenStack keypair, router, security group, and VM instance
+ objects then validates the ping.
+ :return: the exit code from the super.execute() method
+ """
+ try:
+ super(VPingSSH, self).run()
+
+ self.logger.info("Creating keypair with name: '%s'" % self.kp_name)
+ kp_creator = deploy_utils.create_keypair(
+ self.os_creds,
+ KeypairSettings(name=self.kp_name,
+ private_filepath=self.kp_priv_file,
+ public_filepath=self.kp_pub_file))
+ self.creators.append(kp_creator)
+
+ # Creating router to external network
+ self.logger.info("Creating router with name: '%s'"
+ % self.router_name)
+ net_set = self.network_creator.network_settings
+ sub_set = [net_set.subnet_settings[0].name]
+ router_creator = deploy_utils.create_router(
+ self.os_creds,
+ RouterSettings(
+ name=self.router_name,
+ external_gateway=self.ext_net_name,
+ internal_subnets=sub_set))
+ self.creators.append(router_creator)
+
+ # Creating Instance 1
+ port1_settings = PortSettings(
+ name=self.vm1_name + '-vPingPort',
+ network_name=self.network_creator.network_settings.name)
+ instance1_settings = VmInstanceSettings(
+ name=self.vm1_name, flavor=self.flavor_name,
+ vm_boot_timeout=self.vm_boot_timeout,
+ vm_delete_timeout=self.vm_delete_timeout,
+ ssh_connect_timeout=self.vm_ssh_connect_timeout,
+ port_settings=[port1_settings])
+
+ self.logger.info(
+ "Creating VM 1 instance with name: '%s'"
+ % instance1_settings.name)
+ self.vm1_creator = deploy_utils.create_vm_instance(
+ self.os_creds,
+ instance1_settings,
+ self.image_creator.image_settings,
+ keypair_creator=kp_creator)
+ self.creators.append(self.vm1_creator)
+
+ # Creating Instance 2
+ sg_creator = self.__create_security_group()
+ self.creators.append(sg_creator)
+
+ port2_settings = PortSettings(
+ name=self.vm2_name + '-vPingPort',
+ network_name=self.network_creator.network_settings.name)
+ instance2_settings = VmInstanceSettings(
+ name=self.vm2_name, flavor=self.flavor_name,
+ vm_boot_timeout=self.vm_boot_timeout,
+ vm_delete_timeout=self.vm_delete_timeout,
+ ssh_connect_timeout=self.vm_ssh_connect_timeout,
+ port_settings=[port2_settings],
+ security_group_names=[sg_creator.sec_grp_settings.name],
+ floating_ip_settings=[FloatingIpSettings(
+ name=self.vm2_name + '-FIPName',
+ port_name=port2_settings.name,
+ router_name=router_creator.router_settings.name)])
+
+ self.logger.info(
+ "Creating VM 2 instance with name: '%s'"
+ % instance2_settings.name)
+ self.vm2_creator = deploy_utils.create_vm_instance(
+ self.os_creds,
+ instance2_settings,
+ self.image_creator.image_settings,
+ keypair_creator=kp_creator)
+ self.creators.append(self.vm2_creator)
+
+ return self._execute()
+ except Exception as e:
+ self.logger.error('Unexpected error running test - ' + e.message)
+ return TestCase.EX_RUN_ERROR
+ finally:
+ self._cleanup()
+
+ def _do_vping(self, vm_creator, test_ip):
+ """
+ Override from super
+ """
+ if vm_creator.vm_ssh_active(block=True):
+ ssh = vm_creator.ssh_client()
+ if not self.__transfer_ping_script(ssh):
+ return TestCase.EX_RUN_ERROR
+ return self.__do_vping_ssh(ssh, test_ip)
+ else:
+ return -1
+
+ def __transfer_ping_script(self, ssh):
+ """
+ Uses SCP to copy the ping script via the SSH client
+ :param ssh: the SSH client
+ :return:
+ """
+ self.logger.info("Trying to transfer ping.sh")
scp = SCPClient(ssh.get_transport())
local_path = self.functest_repo + "/" + self.repo
ping_script = os.path.join(local_path, "ping.sh")
try:
scp.put(ping_script, "~/")
except:
- self.logger.error("Cannot SCP the file '%s' to VM '%s'"
- % (ping_script, floatip))
+ self.logger.error("Cannot SCP the file '%s'" % ping_script)
return False
cmd = 'chmod 755 ~/ping.sh'
@@ -134,8 +171,14 @@ class VPingSSH(vping_base.VPingBase):
return True
- def do_vping_ssh(self, ssh, test_ip):
- EXIT_CODE = -1
+ def __do_vping_ssh(self, ssh, test_ip):
+ """
+ Pings the test_ip via the SSH client
+ :param ssh: the SSH client used to issue the ping command
+ :param test_ip: the IP for the ping command to use
+ :return: exit_code (int)
+ """
+ exit_code = TestCase.EX_TESTCASE_FAILED
self.logger.info("Waiting for ping...")
sec = 0
@@ -150,7 +193,7 @@ class VPingSSH(vping_base.VPingBase):
for line in output:
if "vPing OK" in line:
self.logger.info("vPing detected!")
- EXIT_CODE = 0
+ exit_code = TestCase.EX_OK
flag = True
break
@@ -162,7 +205,35 @@ class VPingSSH(vping_base.VPingBase):
break
self.logger.debug("Pinging %s. Waiting for response..." % test_ip)
sec += 1
- return EXIT_CODE
+ return exit_code
+
+ def __create_security_group(self):
+ """
+ Configures and deploys an OpenStack security group object
+ :return: the creator object
+ """
+ sg_rules = list()
+ sg_rules.append(
+ SecurityGroupRuleSettings(sec_grp_name=self.sg_name,
+ direction=Direction.ingress,
+ protocol=Protocol.icmp))
+ sg_rules.append(
+ SecurityGroupRuleSettings(sec_grp_name=self.sg_name,
+ direction=Direction.ingress,
+ protocol=Protocol.tcp, port_range_min=22,
+ port_range_max=22))
+ sg_rules.append(
+ SecurityGroupRuleSettings(sec_grp_name=self.sg_name,
+ direction=Direction.egress,
+ protocol=Protocol.tcp, port_range_min=22,
+ port_range_max=22))
+
+ self.logger.info("Security group with name: '%s'" % self.sg_name)
+ return deploy_utils.create_security_group(self.os_creds,
+ SecurityGroupSettings(
+ name=self.sg_name,
+ description=self.sg_desc,
+ rule_settings=sg_rules))
if __name__ == '__main__':
diff --git a/functest/opnfv_tests/openstack/vping/vping_userdata.py b/functest/opnfv_tests/openstack/vping/vping_userdata.py
index 1b00ca23a..8ea9be84b 100755
--- a/functest/opnfv_tests/openstack/vping/vping_userdata.py
+++ b/functest/opnfv_tests/openstack/vping/vping_userdata.py
@@ -7,70 +7,141 @@
#
# http://www.apache.org/licenses/LICENSE-2.0
+import argparse
import sys
import time
-import argparse
+from functest.core.testcase import TestCase
+
+from snaps.openstack.utils import deploy_utils
+from snaps.openstack.create_instance import VmInstanceSettings
+from snaps.openstack.create_network import PortSettings
-import functest.utils.functest_logger as ft_logger
import vping_base
class VPingUserdata(vping_base.VPingBase):
+ """
+ Class to execute the vPing test using userdata and the VM's console
+ """
def __init__(self, **kwargs):
if "case_name" not in kwargs:
kwargs["case_name"] = "vping_userdata"
super(VPingUserdata, self).__init__(**kwargs)
- self.logger = ft_logger.Logger(self.case_name).getLogger()
-
- def boot_vm_preparation(self, config, vmname, test_ip):
- config['config_drive'] = True
- if vmname == self.vm2_name:
- u = ("#!/bin/sh\n\n"
- "while true; do\n"
- " ping -c 1 %s 2>&1 >/dev/null\n"
- " RES=$?\n"
- " if [ \"Z$RES\" = \"Z0\" ] ; then\n"
- " echo 'vPing OK'\n"
- " break\n"
- " else\n"
- " echo 'vPing KO'\n"
- " fi\n"
- " sleep 1\n"
- "done\n" % test_ip)
- config['userdata'] = u
-
- def do_vping(self, vm, test_ip):
+
+ def run(self):
+ """
+ Sets up the OpenStack VM instance objects then executes the ping and
+ validates.
+ :return: the exit code from the super.execute() method
+ """
+ try:
+ super(VPingUserdata, self).run()
+
+ # Creating Instance 1
+ port1_settings = PortSettings(
+ name=self.vm1_name + '-vPingPort',
+ network_name=self.network_creator.network_settings.name)
+ instance1_settings = VmInstanceSettings(
+ name=self.vm1_name,
+ flavor=self.flavor_name,
+ vm_boot_timeout=self.vm_boot_timeout,
+ port_settings=[port1_settings])
+
+ self.logger.info(
+ "Creating VM 1 instance with name: '%s'"
+ % instance1_settings.name)
+ self.vm1_creator = deploy_utils.create_vm_instance(
+ self.os_creds, instance1_settings,
+ self.image_creator.image_settings)
+ self.creators.append(self.vm1_creator)
+
+ userdata = _get_userdata(
+ self.vm1_creator.get_port_ip(port1_settings.name))
+ if userdata:
+ # Creating Instance 2
+ port2_settings = PortSettings(
+ name=self.vm2_name + '-vPingPort',
+ network_name=self.network_creator.network_settings.name)
+ instance2_settings = VmInstanceSettings(
+ name=self.vm2_name,
+ flavor=self.flavor_name,
+ vm_boot_timeout=self.vm_boot_timeout,
+ port_settings=[port2_settings],
+ userdata=userdata)
+
+ self.logger.info(
+ "Creating VM 2 instance with name: '%s'"
+ % instance2_settings.name)
+ self.vm2_creator = deploy_utils.create_vm_instance(
+ self.os_creds, instance2_settings,
+ self.image_creator.image_settings)
+ self.creators.append(self.vm2_creator)
+ else:
+ raise Exception('Userdata is None')
+
+ return self._execute()
+
+ finally:
+ self._cleanup()
+
+ def _do_vping(self, vm_creator, test_ip):
+ """
+ Override from super
+ """
self.logger.info("Waiting for ping...")
- EXIT_CODE = -1
+ exit_code = -1
sec = 0
tries = 0
while True:
time.sleep(1)
- p_console = vm.get_console_output()
+ p_console = vm_creator.get_vm_inst().get_console_output()
if "vPing OK" in p_console:
self.logger.info("vPing detected!")
- EXIT_CODE = 0
+ exit_code = TestCase.EX_OK
break
elif "failed to read iid from metadata" in p_console or tries > 5:
- EXIT_CODE = -2
+ exit_code = TestCase.EX_TESTCASE_FAILED
break
elif sec == self.ping_timeout:
self.logger.info("Timeout reached.")
break
elif sec % 10 == 0:
if "request failed" in p_console:
- self.logger.debug("It seems userdata is not supported "
- "in nova boot. Waiting a bit...")
+ self.logger.debug(
+ "It seems userdata is not supported in nova boot. " +
+ "Waiting a bit...")
tries += 1
else:
- self.logger.debug("Pinging %s. Waiting for response..."
- % test_ip)
+ self.logger.debug(
+ "Pinging %s. Waiting for response..." % test_ip)
sec += 1
- return EXIT_CODE
+ return exit_code
+
+
+def _get_userdata(test_ip):
+ """
+ Returns the post VM creation script to be added into the VM's userdata
+ :param test_ip: the IP value to substitute into the script
+ :return: the bash script contents
+ """
+ if test_ip:
+ return ("#!/bin/sh\n\n"
+ "while true; do\n"
+ " ping -c 1 %s 2>&1 >/dev/null\n"
+ " RES=$?\n"
+ " if [ \"Z$RES\" = \"Z0\" ] ; then\n"
+ " echo 'vPing OK'\n"
+ " break\n"
+ " else\n"
+ " echo 'vPing KO'\n"
+ " fi\n"
+ " sleep 1\n"
+ "done\n" % test_ip)
+ return None
if __name__ == '__main__':
diff --git a/functest/opnfv_tests/sdn/odl/odl.py b/functest/opnfv_tests/sdn/odl/odl.py
index 6f4acf6dd..6f586b7a0 100755
--- a/functest/opnfv_tests/sdn/odl/odl.py
+++ b/functest/opnfv_tests/sdn/odl/odl.py
@@ -16,21 +16,23 @@ Example:
$ python odl.py
"""
+from __future__ import division
+
import argparse
import errno
import fileinput
+import logging
import os
import re
import sys
-import urlparse
import robot.api
from robot.errors import RobotError
import robot.run
from robot.utils.robottime import timestamp_to_secs
+from six.moves import urllib
from functest.core import testcase
-import functest.utils.functest_logger as ft_logger
import functest.utils.openstack_utils as op_utils
__author__ = "Cedric Ollivier <cedric.ollivier@orange.com>"
@@ -70,7 +72,7 @@ class ODLTests(testcase.TestCase):
"csit/suites/integration/basic")
default_suites = [basic_suite_dir, neutron_suite_dir]
res_dir = '/home/opnfv/functest/results/odl/'
- logger = ft_logger.Logger("opendaylight").getLogger()
+ __logger = logging.getLogger(__name__)
@classmethod
def set_robotframework_vars(cls, odlusername="admin", odlpassword="admin"):
@@ -85,13 +87,13 @@ class ODLTests(testcase.TestCase):
try:
for line in fileinput.input(odl_variables_files,
inplace=True):
- print re.sub("AUTH = .*",
+ print(re.sub("AUTH = .*",
("AUTH = [u'" + odlusername + "', u'" +
odlpassword + "']"),
- line.rstrip())
+ line.rstrip()))
return True
except Exception as ex: # pylint: disable=broad-except
- cls.logger.error("Cannot set ODL creds: %s", str(ex))
+ cls.__logger.error("Cannot set ODL creds: %s", str(ex))
return False
def parse_results(self):
@@ -100,7 +102,12 @@ class ODLTests(testcase.TestCase):
result = robot.api.ExecutionResult(xml_file)
visitor = ODLResultVisitor()
result.visit(visitor)
- self.result = result.suite.status
+ try:
+ self.result = 100 * (
+ result.suite.statistics.critical.passed /
+ result.suite.statistics.critical.total)
+ except ZeroDivisionError:
+ self.__logger.error("No test has been ran")
self.start_time = timestamp_to_secs(result.suite.starttime)
self.stop_time = timestamp_to_secs(result.suite.endtime)
self.details = {}
@@ -143,7 +150,7 @@ class ODLTests(testcase.TestCase):
odlusername = kwargs['odlusername']
odlpassword = kwargs['odlpassword']
osauthurl = kwargs['osauthurl']
- keystoneip = urlparse.urlparse(osauthurl).hostname
+ keystoneip = urllib.parse.urlparse(osauthurl).hostname
variables = ['KEYSTONE:' + keystoneip,
'NEUTRON:' + kwargs['neutronip'],
'OS_AUTH_URL:"' + osauthurl + '"',
@@ -154,15 +161,15 @@ class ODLTests(testcase.TestCase):
'PORT:' + kwargs['odlwebport'],
'RESTCONFPORT:' + kwargs['odlrestconfport']]
except KeyError as ex:
- self.logger.error("Cannot run ODL testcases. Please check "
- "%s", str(ex))
+ self.__logger.error("Cannot run ODL testcases. Please check "
+ "%s", str(ex))
return self.EX_RUN_ERROR
if self.set_robotframework_vars(odlusername, odlpassword):
try:
os.makedirs(self.res_dir)
except OSError as ex:
if ex.errno != errno.EEXIST:
- self.logger.exception(
+ self.__logger.exception(
"Cannot create %s", self.res_dir)
return self.EX_RUN_ERROR
stdout_file = os.path.join(self.res_dir, 'stdout.txt')
@@ -174,19 +181,19 @@ class ODLTests(testcase.TestCase):
report='NONE',
stdout=stdout)
stdout.seek(0, 0)
- self.logger.info("\n" + stdout.read())
- self.logger.info("ODL results were successfully generated")
+ self.__logger.info("\n" + stdout.read())
+ self.__logger.info("ODL results were successfully generated")
try:
self.parse_results()
- self.logger.info("ODL results were successfully parsed")
+ self.__logger.info("ODL results were successfully parsed")
except RobotError as ex:
- self.logger.error("Run tests before publishing: %s",
- ex.message)
+ self.__logger.error("Run tests before publishing: %s",
+ ex.message)
return self.EX_RUN_ERROR
try:
os.remove(stdout_file)
except OSError:
- self.logger.warning("Cannot remove %s", stdout_file)
+ self.__logger.warning("Cannot remove %s", stdout_file)
return self.EX_OK
else:
return self.EX_RUN_ERROR
@@ -211,7 +218,7 @@ class ODLTests(testcase.TestCase):
except KeyError:
pass
neutron_url = op_utils.get_endpoint(service_type='network')
- kwargs = {'neutronip': urlparse.urlparse(neutron_url).hostname}
+ kwargs = {'neutronip': urllib.parse.urlparse(neutron_url).hostname}
kwargs['odlip'] = kwargs['neutronip']
kwargs['odlwebport'] = '8080'
kwargs['odlrestconfport'] = '8181'
@@ -237,12 +244,12 @@ class ODLTests(testcase.TestCase):
else:
kwargs['odlip'] = os.environ['SDN_CONTROLLER_IP']
except KeyError as ex:
- self.logger.error("Cannot run ODL testcases. "
- "Please check env var: "
- "%s", str(ex))
+ self.__logger.error("Cannot run ODL testcases. "
+ "Please check env var: "
+ "%s", str(ex))
return self.EX_RUN_ERROR
except Exception: # pylint: disable=broad-except
- self.logger.exception("Cannot run ODL testcases.")
+ self.__logger.exception("Cannot run ODL testcases.")
return self.EX_RUN_ERROR
return self.main(suites, **kwargs)
@@ -301,6 +308,7 @@ class ODLParser(object): # pylint: disable=too-few-public-methods
if __name__ == '__main__':
+ logging.basicConfig()
ODL = ODLTests()
PARSER = ODLParser()
ARGS = PARSER.parse_args(sys.argv[1:])
diff --git a/functest/opnfv_tests/sdn/onos/onos.py b/functest/opnfv_tests/sdn/onos/onos.py
index 4d489d674..5dfff036b 100644
--- a/functest/opnfv_tests/sdn/onos/onos.py
+++ b/functest/opnfv_tests/sdn/onos/onos.py
@@ -7,6 +7,7 @@
# which accompanies this distribution, and is available at
# http://www.apache.org/licenses/LICENSE-2.0
+import logging
import os
import re
import subprocess
@@ -16,7 +17,6 @@ import urlparse
from functest.core import testcase
from functest.utils.constants import CONST
-import functest.utils.functest_logger as ft_logger
import functest.utils.functest_utils as ft_utils
import functest.utils.openstack_utils as openstack_utils
@@ -25,12 +25,12 @@ class OnosBase(testcase.TestCase):
onos_repo_path = CONST.__getattribute__('dir_repo_onos')
onos_sfc_image_name = CONST.__getattribute__('onos_sfc_image_name')
onos_sfc_image_path = os.path.join(
- CONST.__getattribute__('dir_functest_data'),
+ CONST.__getattribute__('dir_functest_images'),
CONST.__getattribute__('onos_sfc_image_file_name'))
onos_sfc_path = os.path.join(CONST.__getattribute__('dir_repo_functest'),
CONST.__getattribute__('dir_onos_sfc'))
installer_type = CONST.__getattribute__('INSTALLER_TYPE')
- logger = ft_logger.Logger(__name__).getLogger()
+ logger = logging.getLogger(__name__)
def __init__(self, **kwargs):
if "case_name" not in kwargs:
diff --git a/functest/opnfv_tests/sdn/onos/sfc/sfc.py b/functest/opnfv_tests/sdn/onos/sfc/sfc.py
index 22412270a..0155d24d7 100755
--- a/functest/opnfv_tests/sdn/onos/sfc/sfc.py
+++ b/functest/opnfv_tests/sdn/onos/sfc/sfc.py
@@ -1,4 +1,3 @@
-"""Script to Test the SFC scenarios in ONOS."""
# !/usr/bin/python
#
# Copyright (c) CREATED5 All rights reserved
@@ -22,13 +21,14 @@
# Testcase 7 : Cleanup
# ###########################################################################
#
+"""Script to Test the SFC scenarios in ONOS."""
+import logging
import time
-import functest.utils.functest_logger as ft_logger
import functest.utils.functest_utils as ft_utils
from sfc_onos import SfcOnos
-logger = ft_logger.Logger("sfc").getLogger()
+logger = logging.getLogger(__name__)
Sfc_obj = SfcOnos()
OK = 200
@@ -174,4 +174,5 @@ def main():
if __name__ == '__main__':
+ logging.basicConfig()
main()
diff --git a/functest/opnfv_tests/sdn/onos/sfc/sfc_onos.py b/functest/opnfv_tests/sdn/onos/sfc/sfc_onos.py
index c21986902..1101f2394 100644
--- a/functest/opnfv_tests/sdn/onos/sfc/sfc_onos.py
+++ b/functest/opnfv_tests/sdn/onos/sfc/sfc_onos.py
@@ -1,3 +1,4 @@
+import logging
import os
import re
import time
@@ -8,8 +9,6 @@ from multiprocessing import Process
from multiprocessing import Queue
from pexpect import pxssh
-import functest.utils.functest_logger as ft_logger
-
from functest.utils.constants import CONST
OK = 200
@@ -23,7 +22,7 @@ class SfcOnos(object):
def __init__(self):
"""Initialization of variables."""
- self.logger = ft_logger.Logger("sfc_fun").getLogger()
+ self.logger = logging.getLogger(__name__)
self.osver = "v2.0"
self.token_id = 0
self.net_id = 0
diff --git a/functest/opnfv_tests/sdn/onos/teston/adapters/client.py b/functest/opnfv_tests/sdn/onos/teston/adapters/client.py
index 81d5f7d79..a88d2f067 100644
--- a/functest/opnfv_tests/sdn/onos/teston/adapters/client.py
+++ b/functest/opnfv_tests/sdn/onos/teston/adapters/client.py
@@ -11,17 +11,17 @@ Description:
#
"""
import json
+import logging
import pexpect
import requests
import time
from environment import Environment
-import functest.utils.functest_logger as ft_logger
class Client(Environment):
- logger = ft_logger.Logger("client").getLogger()
+ logger = logging.getLogger(__name__)
def __init__(self):
Environment.__init__(self)
diff --git a/functest/opnfv_tests/sdn/onos/teston/adapters/connection.py b/functest/opnfv_tests/sdn/onos/teston/adapters/connection.py
index 3786945d2..dfaa5cc14 100644
--- a/functest/opnfv_tests/sdn/onos/teston/adapters/connection.py
+++ b/functest/opnfv_tests/sdn/onos/teston/adapters/connection.py
@@ -13,17 +13,17 @@ Description:
# http://www.apache.org/licenses/LICENSE-2.0
#
"""
+import logging
import os
import pexpect
import re
from foundation import Foundation
-import functest.utils.functest_logger as ft_logger
class Connection(Foundation):
- logger = ft_logger.Logger("connection").getLogger()
+ logger = logging.getLogger(__name__)
def __init__(self):
Foundation.__init__(self)
diff --git a/functest/opnfv_tests/sdn/onos/teston/adapters/environment.py b/functest/opnfv_tests/sdn/onos/teston/adapters/environment.py
index 046a821d4..cb75b5c3c 100644
--- a/functest/opnfv_tests/sdn/onos/teston/adapters/environment.py
+++ b/functest/opnfv_tests/sdn/onos/teston/adapters/environment.py
@@ -15,6 +15,7 @@ Description:
#
"""
+import logging
import pexpect
import pxssh
import re
@@ -23,12 +24,11 @@ import sys
import time
from connection import Connection
-import functest.utils.functest_logger as ft_logger
class Environment(Connection):
- logger = ft_logger.Logger("environment").getLogger()
+ logger = logging.getLogger(__name__)
def __init__(self):
Connection.__init__(self)
diff --git a/functest/opnfv_tests/vnf/aaa/aaa.py b/functest/opnfv_tests/vnf/aaa/aaa.py
index 9c94cfb1a..0030256c2 100755
--- a/functest/opnfv_tests/vnf/aaa/aaa.py
+++ b/functest/opnfv_tests/vnf/aaa/aaa.py
@@ -7,18 +7,18 @@
# which accompanies this distribution, and is available at
# http://www.apache.org/licenses/LICENSE-2.0
+import logging
import sys
import argparse
import functest.core.testcase as testcase
-import functest.core.vnf_base as vnf_base
-import functest.utils.functest_logger as ft_logger
+import functest.core.vnf as vnf
-class AaaVnf(vnf_base.VnfOnBoardingBase):
+class AaaVnf(vnf.VnfOnBoarding):
- logger = ft_logger.Logger("VNF AAA").getLogger()
+ logger = logging.getLogger(__name__)
def __init__(self, **kwargs):
if "case_name" not in kwargs:
@@ -60,6 +60,7 @@ class AaaVnf(vnf_base.VnfOnBoardingBase):
if __name__ == '__main__':
+ logging.basicConfig()
parser = argparse.ArgumentParser()
args = vars(parser.parse_args())
aaa_vnf = AaaVnf()
diff --git a/functest/opnfv_tests/vnf/ims/clearwater_ims_base.py b/functest/opnfv_tests/vnf/ims/clearwater_ims_base.py
index 494633f4f..42d31e3bb 100644
--- a/functest/opnfv_tests/vnf/ims/clearwater_ims_base.py
+++ b/functest/opnfv_tests/vnf/ims/clearwater_ims_base.py
@@ -7,21 +7,21 @@
#
# http://www.apache.org/licenses/LICENSE-2.0
import json
+import logging
import os
import shutil
import requests
-import functest.core.vnf_base as vnf_base
+import functest.core.vnf as vnf
from functest.utils.constants import CONST
-import functest.utils.functest_logger as ft_logger
import functest.utils.functest_utils as ft_utils
-class ClearwaterOnBoardingBase(vnf_base.VnfOnBoardingBase):
+class ClearwaterOnBoardingBase(vnf.VnfOnBoarding):
def __init__(self, **kwargs):
- self.logger = ft_logger.Logger(__name__).getLogger()
+ self.logger = logging.getLogger(__name__)
super(ClearwaterOnBoardingBase, self).__init__(**kwargs)
self.case_dir = os.path.join(CONST.dir_functest_test, 'vnf', 'ims')
self.data_dir = CONST.dir_ims_data
diff --git a/functest/opnfv_tests/vnf/ims/cloudify_ims.py b/functest/opnfv_tests/vnf/ims/cloudify_ims.py
index 0e6d47970..ba4c57901 100644
--- a/functest/opnfv_tests/vnf/ims/cloudify_ims.py
+++ b/functest/opnfv_tests/vnf/ims/cloudify_ims.py
@@ -7,6 +7,7 @@
# which accompanies this distribution, and is available at
# http://www.apache.org/licenses/LICENSE-2.0
+import logging
import os
import sys
import time
@@ -18,7 +19,6 @@ from functest.opnfv_tests.vnf.ims.clearwater import Clearwater
import functest.opnfv_tests.vnf.ims.clearwater_ims_base as clearwater_ims_base
from functest.opnfv_tests.vnf.ims.orchestrator_cloudify import Orchestrator
from functest.utils.constants import CONST
-import functest.utils.functest_logger as ft_logger
import functest.utils.functest_utils as ft_utils
import functest.utils.openstack_utils as os_utils
@@ -29,7 +29,7 @@ class CloudifyIms(clearwater_ims_base.ClearwaterOnBoardingBase):
if "case_name" not in kwargs:
kwargs["case_name"] = "cloudify_ims"
super(CloudifyIms, self).__init__(**kwargs)
- self.logger = ft_logger.Logger(__name__).getLogger()
+ self.logger = logging.getLogger(__name__)
# Retrieve the configuration
try:
diff --git a/functest/opnfv_tests/vnf/ims/opera_ims.py b/functest/opnfv_tests/vnf/ims/opera_ims.py
index a46f9d71f..8c33d16e8 100644
--- a/functest/opnfv_tests/vnf/ims/opera_ims.py
+++ b/functest/opnfv_tests/vnf/ims/opera_ims.py
@@ -8,6 +8,7 @@
# http://www.apache.org/licenses/LICENSE-2.0
import json
+import logging
import os
import time
@@ -15,16 +16,15 @@ from opera import openo_connect
import requests
import functest.opnfv_tests.vnf.ims.clearwater_ims_base as clearwater_ims_base
-from functest.utils.constants import CONST
-import functest.utils.functest_logger as ft_logger
class OperaIms(clearwater_ims_base.ClearwaterOnBoardingBase):
- def __init__(self, project='functest', case_name='opera_ims',
- repo=CONST.dir_repo_opera, cmd=''):
- super(OperaIms, self).__init__(project, case_name, repo, cmd)
- self.logger = ft_logger.Logger(__name__).getLogger()
+ def __init__(self, **kwargs):
+ if "case_name" not in kwargs:
+ kwargs["case_name"] = "opera_ims"
+ super(OperaIms, self).__init__(**kwargs)
+ self.logger = logging.getLogger(__name__)
self.ellis_file = os.path.join(self.result_dir, 'ellis.info')
self.live_test_file = os.path.join(self.result_dir,
'live_test_report.json')
@@ -64,27 +64,27 @@ class OperaIms(clearwater_ims_base.ClearwaterOnBoardingBase):
self.logger.info('VNFM IP: %s', vnfm_ip)
vnf_status_url = 'http://{0}:5000/api/v1/model/status'.format(vnfm_ip)
vnf_alive = False
- retry = 15
+ retry = 40
self.logger.info('Check the VNF status')
while retry > 0:
- rq = requests.get(vnf_status_url)
+ rq = requests.get(vnf_status_url, timeout=90)
response = rq.json()
vnf_alive = response['vnf_alive']
msg = response['msg']
self.logger.info(msg)
if vnf_alive:
break
- self.logger.info('check again in one minute...')
+ self.logger.info('check again in one and half a minute...')
retry = retry - 1
- time.sleep(60)
+ time.sleep(90)
if not vnf_alive:
raise Exception('VNF failed to start: {0}'.format(msg))
ellis_config_url = ('http://{0}:5000/api/v1/model/ellis/configure'
.format(vnfm_ip))
- rq = requests.get(ellis_config_url, timeout=60)
+ rq = requests.get(ellis_config_url, timeout=90)
if rq.json() and not rq.json()['ellis_ok']:
self.logger.error(rq.json()['data'])
raise Exception('Failed to configure Ellis')
@@ -92,7 +92,7 @@ class OperaIms(clearwater_ims_base.ClearwaterOnBoardingBase):
self.logger.info('Get Clearwater deployment detail')
vnf_info_url = ('http://{0}:5000/api/v1/model/output'
.format(vnfm_ip))
- rq = requests.get(vnf_info_url, timeout=60)
+ rq = requests.get(vnf_info_url, timeout=90)
data = rq.json()['data']
self.logger.info(data)
bono_ip = data['bono_ip']
diff --git a/functest/opnfv_tests/vnf/ims/orchestra_ims.py b/functest/opnfv_tests/vnf/ims/orchestra_ims.py
index 351c5fbe2..6f341970d 100755
--- a/functest/opnfv_tests/vnf/ims/orchestra_ims.py
+++ b/functest/opnfv_tests/vnf/ims/orchestra_ims.py
@@ -8,16 +8,16 @@
# http://www.apache.org/licenses/LICENSE-2.0
import json
+import logging
+import os
import socket
import sys
import time
import yaml
-import functest.core.vnf_base as vnf_base
-import functest.utils.functest_logger as ft_logger
+import functest.core.vnf as vnf
import functest.utils.functest_utils as ft_utils
import functest.utils.openstack_utils as os_utils
-import os
from functest.utils.constants import CONST
from org.openbaton.cli.agents.agents import MainAgent
@@ -76,7 +76,7 @@ def servertest(host, port):
return True
-class ImsVnf(vnf_base.VnfOnBoardingBase):
+class ImsVnf(vnf.VnfOnBoarding):
def __init__(self, project='functest', case_name='orchestra_ims',
repo='', cmd=''):
@@ -87,7 +87,7 @@ class ImsVnf(vnf_base.VnfOnBoardingBase):
self.ob_port = "8080"
self.ob_ip = "localhost"
self.ob_instance_id = ""
- self.logger = ft_logger.Logger("orchestra_ims").getLogger()
+ self.logger = logging.getLogger(__name__)
self.case_dir = os.path.join(CONST.dir_functest_test, 'vnf/ims/')
self.data_dir = CONST.dir_ims_data
self.test_dir = CONST.dir_repo_vims_test
@@ -495,6 +495,7 @@ class ImsVnf(vnf_base.VnfOnBoardingBase):
if __name__ == '__main__':
+ logging.basicConfig()
test = ImsVnf()
test.deploy_orchestrator()
test.deploy_vnf()
diff --git a/functest/opnfv_tests/vnf/ims/orchestrator_cloudify.py b/functest/opnfv_tests/vnf/ims/orchestrator_cloudify.py
index 82a9dca05..4ceeb25f8 100644
--- a/functest/opnfv_tests/vnf/ims/orchestrator_cloudify.py
+++ b/functest/opnfv_tests/vnf/ims/orchestrator_cloudify.py
@@ -11,6 +11,7 @@
# http://www.apache.org/licenses/LICENSE-2.0
########################################################################
+import logging
import os
import shutil
import subprocess32 as subprocess
@@ -18,8 +19,6 @@ import yaml
from git import Repo
-import functest.utils.functest_logger as ft_logger
-
class Orchestrator(object):
@@ -29,7 +28,7 @@ class Orchestrator(object):
self.input_file = 'inputs.yaml'
self.manager_blueprint = False
self.config = inputs
- self.logger = ft_logger.Logger("Orchestrator").getLogger()
+ self.logger = logging.getLogger(__name__)
self.manager_up = False
def set_credentials(self, username, password, tenant_name, auth_url):
diff --git a/functest/tests/unit/ci/test_generate_report.py b/functest/tests/unit/ci/test_generate_report.py
deleted file mode 100644
index 2225586f2..000000000
--- a/functest/tests/unit/ci/test_generate_report.py
+++ /dev/null
@@ -1,129 +0,0 @@
-#!/usr/bin/env python
-
-# 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 logging
-import unittest
-import urllib2
-
-import mock
-
-from functest.ci import generate_report as gen_report
-from functest.tests.unit import test_utils
-from functest.utils import functest_utils as ft_utils
-from functest.utils.constants import CONST
-
-
-class GenerateReportTesting(unittest.TestCase):
-
- logging.disable(logging.CRITICAL)
-
- def test_init(self):
- test_array = gen_report.init()
- self.assertEqual(test_array, [])
-
- @mock.patch('functest.ci.generate_report.urllib2.urlopen',
- side_effect=urllib2.URLError('no host given'))
- def test_get_results_from_db_fail(self, mock_method):
- url = "%s/results?build_tag=%s" % (ft_utils.get_db_url(),
- CONST.BUILD_TAG)
- self.assertIsNone(gen_report.get_results_from_db())
- mock_method.assert_called_once_with(url)
-
- @mock.patch('functest.ci.generate_report.urllib2.urlopen',
- return_value={'results': []})
- def test_get_results_from_db_success(self, mock_method):
- url = "%s/results?build_tag=%s" % (ft_utils.get_db_url(),
- CONST.BUILD_TAG)
- self.assertEqual(gen_report.get_results_from_db(), None)
- mock_method.assert_called_once_with(url)
-
- def test_get_data(self):
- self.assertIsInstance(gen_report.get_data({'result': ''}, ''), dict)
-
- def test_print_line_with_ci_run(self):
- CONST.IS_CI_RUN = True
- w1 = 'test_print_line'
- test_str = ("| %s| %s| %s| %s| %s|\n"
- % (w1.ljust(gen_report.COL_1_LEN - 1),
- ''.ljust(gen_report.COL_2_LEN - 1),
- ''.ljust(gen_report.COL_3_LEN - 1),
- ''.ljust(gen_report.COL_4_LEN - 1),
- ''.ljust(gen_report.COL_5_LEN - 1)))
- self.assertEqual(gen_report.print_line(w1), test_str)
-
- def test_print_line_without_ci_run(self):
- CONST.IS_CI_RUN = False
- w1 = 'test_print_line'
- test_str = ("| %s| %s| %s| %s|\n"
- % (w1.ljust(gen_report.COL_1_LEN - 1),
- ''.ljust(gen_report.COL_2_LEN - 1),
- ''.ljust(gen_report.COL_3_LEN - 1),
- ''.ljust(gen_report.COL_4_LEN - 1)))
- self.assertEqual(gen_report.print_line(w1), test_str)
-
- def test_print_line_no_column_with_ci_run(self):
- CONST.IS_CI_RUN = True
- TOTAL_LEN = gen_report.COL_1_LEN + gen_report.COL_2_LEN
- TOTAL_LEN += gen_report.COL_3_LEN + gen_report.COL_4_LEN + 2
- TOTAL_LEN += gen_report.COL_5_LEN + 1
- test_str = ("| %s|\n" % 'test'.ljust(TOTAL_LEN))
- self.assertEqual(gen_report.print_line_no_columns('test'), test_str)
-
- def test_print_line_no_column_without_ci_run(self):
- CONST.IS_CI_RUN = False
- TOTAL_LEN = gen_report.COL_1_LEN + gen_report.COL_2_LEN
- TOTAL_LEN += gen_report.COL_3_LEN + gen_report.COL_4_LEN + 2
- test_str = ("| %s|\n" % 'test'.ljust(TOTAL_LEN))
- self.assertEqual(gen_report.print_line_no_columns('test'), test_str)
-
- def test_print_separator_with_ci_run(self):
- CONST.IS_CI_RUN = True
- test_str = ("+" + "=" * gen_report.COL_1_LEN +
- "+" + "=" * gen_report.COL_2_LEN +
- "+" + "=" * gen_report.COL_3_LEN +
- "+" + "=" * gen_report.COL_4_LEN +
- "+" + "=" * gen_report.COL_5_LEN)
- test_str += '+\n'
- self.assertEqual(gen_report.print_separator(), test_str)
-
- def test_print_separator_without_ci_run(self):
- CONST.IS_CI_RUN = False
- test_str = ("+" + "=" * gen_report.COL_1_LEN +
- "+" + "=" * gen_report.COL_2_LEN +
- "+" + "=" * gen_report.COL_3_LEN +
- "+" + "=" * gen_report.COL_4_LEN)
- test_str += "+\n"
- self.assertEqual(gen_report.print_separator(), test_str)
-
- @mock.patch('functest.ci.generate_report.logger.info')
- def test_main_with_ci_run(self, mock_method):
- CONST.IS_CI_RUN = True
- gen_report.main()
- mock_method.assert_called_once_with(test_utils.SubstrMatch('URL'))
-
- @mock.patch('functest.ci.generate_report.logger.info')
- def test_main_with_ci_loop(self, mock_method):
- CONST.CI_LOOP = 'daily'
- gen_report.main()
- mock_method.assert_called_once_with(test_utils.SubstrMatch('CI LOOP'))
-
- @mock.patch('functest.ci.generate_report.logger.info')
- def test_main_with_scenario(self, mock_method):
- CONST.DEPLOY_SCENARIO = 'test_scenario'
- gen_report.main()
- mock_method.assert_called_once_with(test_utils.SubstrMatch('SCENARIO'))
-
- @mock.patch('functest.ci.generate_report.logger.info')
- def test_main_with_build_tag(self, mock_method):
- CONST.BUILD_TAG = 'test_build_tag'
- gen_report.main()
- mock_method.assert_called_once_with(test_utils.
- SubstrMatch('BUILD TAG'))
-
-
-if __name__ == "__main__":
- unittest.main(verbosity=2)
diff --git a/functest/tests/unit/ci/test_prepare_env.py b/functest/tests/unit/ci/test_prepare_env.py
index 714dd13c3..fbb596512 100644
--- a/functest/tests/unit/ci/test_prepare_env.py
+++ b/functest/tests/unit/ci/test_prepare_env.py
@@ -33,7 +33,7 @@ class PrepareEnvTesting(unittest.TestCase):
@mock.patch('functest.ci.prepare_env.logger.warning')
def test_check_env_variables_missing_inst_type(self, mock_logger_warn,
mock_logger_info):
- CONST.INSTALLER_TYPE = None
+ CONST.__setattr__('INSTALLER_TYPE', None)
prepare_env.check_env_variables()
mock_logger_info.assert_any_call("Checking environment variables"
"...")
@@ -44,7 +44,7 @@ class PrepareEnvTesting(unittest.TestCase):
@mock.patch('functest.ci.prepare_env.logger.warning')
def test_check_env_variables_missing_inst_ip(self, mock_logger_warn,
mock_logger_info):
- CONST.INSTALLER_IP = None
+ CONST.__setattr__('INSTALLER_IP', None)
prepare_env.check_env_variables()
mock_logger_info.assert_any_call("Checking environment variables"
"...")
@@ -61,7 +61,7 @@ class PrepareEnvTesting(unittest.TestCase):
@mock.patch('functest.ci.prepare_env.logger.warning')
def test_check_env_variables_with_inst_ip(self, mock_logger_warn,
mock_logger_info):
- CONST.INSTALLER_IP = mock.Mock()
+ CONST.__setattr__('INSTALLER_IP', mock.Mock())
prepare_env.check_env_variables()
mock_logger_info.assert_any_call("Checking environment variables"
"...")
@@ -72,7 +72,7 @@ class PrepareEnvTesting(unittest.TestCase):
@mock.patch('functest.ci.prepare_env.logger.warning')
def test_check_env_variables_missing_scenario(self, mock_logger_warn,
mock_logger_info):
- CONST.DEPLOY_SCENARIO = None
+ CONST.__setattr__('DEPLOY_SCENARIO', None)
prepare_env.check_env_variables()
mock_logger_info.assert_any_call("Checking environment variables"
"...")
@@ -84,7 +84,7 @@ class PrepareEnvTesting(unittest.TestCase):
@mock.patch('functest.ci.prepare_env.logger.warning')
def test_check_env_variables_with_scenario(self, mock_logger_warn,
mock_logger_info):
- CONST.DEPLOY_SCENARIO = 'test_scenario'
+ CONST.__setattr__('DEPLOY_SCENARIO', 'test_scenario')
prepare_env.check_env_variables()
mock_logger_info.assert_any_call("Checking environment variables"
"...")
@@ -95,7 +95,7 @@ class PrepareEnvTesting(unittest.TestCase):
@mock.patch('functest.ci.prepare_env.logger.warning')
def test_check_env_variables_with_ci_debug(self, mock_logger_warn,
mock_logger_info):
- CONST.CI_DEBUG = mock.Mock()
+ CONST.__setattr__('CI_DEBUG', mock.Mock())
prepare_env.check_env_variables()
mock_logger_info.assert_any_call("Checking environment variables"
"...")
@@ -106,7 +106,7 @@ class PrepareEnvTesting(unittest.TestCase):
@mock.patch('functest.ci.prepare_env.logger.warning')
def test_check_env_variables_with_node(self, mock_logger_warn,
mock_logger_info):
- CONST.NODE_NAME = mock.Mock()
+ CONST.__setattr__('NODE_NAME', mock.Mock())
prepare_env.check_env_variables()
mock_logger_info.assert_any_call("Checking environment variables"
"...")
@@ -117,7 +117,7 @@ class PrepareEnvTesting(unittest.TestCase):
@mock.patch('functest.ci.prepare_env.logger.warning')
def test_check_env_variables_with_build_tag(self, mock_logger_warn,
mock_logger_info):
- CONST.BUILD_TAG = mock.Mock()
+ CONST.__setattr__('BUILD_TAG', mock.Mock())
prepare_env.check_env_variables()
mock_logger_info.assert_any_call("Checking environment variables"
"...")
@@ -129,7 +129,7 @@ class PrepareEnvTesting(unittest.TestCase):
@mock.patch('functest.ci.prepare_env.logger.warning')
def test_check_env_variables_with_is_ci_run(self, mock_logger_warn,
mock_logger_info):
- CONST.IS_CI_RUN = mock.Mock()
+ CONST.__setattr__('IS_CI_RUN', mock.Mock())
prepare_env.check_env_variables()
mock_logger_info.assert_any_call("Checking environment variables"
"...")
@@ -140,11 +140,11 @@ class PrepareEnvTesting(unittest.TestCase):
def test_get_deployment_handler_missing_const_vars(self):
with mock.patch('functest.ci.prepare_env.'
'factory.Factory.get_handler') as m:
- CONST.INSTALLER_IP = None
+ CONST.__setattr__('INSTALLER_IP', None)
prepare_env.get_deployment_handler()
self.assertFalse(m.called)
- CONST.INSTALLER_TYPE = None
+ CONST.__setattr__('INSTALLER_TYPE', None)
prepare_env.get_deployment_handler()
self.assertFalse(m.called)
@@ -156,8 +156,8 @@ class PrepareEnvTesting(unittest.TestCase):
mock.patch('functest.ci.prepare_env.'
'ft_utils.get_parameter_from_yaml',
side_effect=ValueError):
- CONST.INSTALLER_IP = 'test_ip'
- CONST.INSTALLER_TYPE = 'test_inst_type'
+ CONST.__setattr__('INSTALLER_IP', 'test_ip')
+ CONST.__setattr__('INSTALLER_TYPE', 'test_inst_type')
opnfv_constants.INSTALLERS = ['test_inst_type']
prepare_env.get_deployment_handler()
msg = ('Printing deployment info is not supported for '
@@ -172,8 +172,8 @@ class PrepareEnvTesting(unittest.TestCase):
side_effect=Exception), \
mock.patch('functest.ci.prepare_env.'
'ft_utils.get_parameter_from_yaml'):
- CONST.INSTALLER_IP = 'test_ip'
- CONST.INSTALLER_TYPE = 'test_inst_type'
+ CONST.__setattr__('INSTALLER_IP', 'test_ip')
+ CONST.__setattr__('INSTALLER_TYPE', 'test_inst_type')
opnfv_constants.INSTALLERS = ['test_inst_type']
prepare_env.get_deployment_handler()
self.assertTrue(mock_debug.called)
@@ -188,12 +188,21 @@ class PrepareEnvTesting(unittest.TestCase):
as mock_method:
prepare_env.create_directories()
mock_logger_info.assert_any_call("Creating needed directories...")
- mock_method.assert_any_call(CONST.dir_functest_conf)
- mock_method.assert_any_call(CONST.dir_functest_data)
+ mock_method.assert_any_call(
+ CONST.__getattribute__('dir_functest_conf'))
+ mock_method.assert_any_call(
+ CONST.__getattribute__('dir_functest_data'))
+ mock_method.assert_any_call(
+ CONST.__getattribute__('dir_functest_images'))
mock_logger_info.assert_any_call(" %s created." %
- CONST.dir_functest_conf)
+ CONST.__getattribute__(
+ 'dir_functest_conf'))
mock_logger_info.assert_any_call(" %s created." %
- CONST.dir_functest_data)
+ CONST.__getattribute__(
+ 'dir_functest_data'))
+ mock_logger_info.assert_any_call(" %s created." %
+ CONST.__getattribute__(
+ 'dir_functest_images'))
@mock.patch('functest.ci.prepare_env.logger.info')
@mock.patch('functest.ci.prepare_env.logger.debug')
@@ -204,9 +213,14 @@ class PrepareEnvTesting(unittest.TestCase):
prepare_env.create_directories()
mock_logger_info.assert_any_call("Creating needed directories...")
mock_logger_debug.assert_any_call(" %s already exists." %
- CONST.dir_functest_conf)
+ CONST.__getattribute__(
+ 'dir_functest_conf'))
+ mock_logger_debug.assert_any_call(" %s already exists." %
+ CONST.__getattribute__(
+ 'dir_functest_data'))
mock_logger_debug.assert_any_call(" %s already exists." %
- CONST.dir_functest_data)
+ CONST.__getattribute__(
+ 'dir_functest_images'))
def _get_env_cred_dict(self, os_prefix=''):
return {'OS_USERNAME': os_prefix + 'username',
@@ -230,24 +244,24 @@ class PrepareEnvTesting(unittest.TestCase):
mock.patch('functest.ci.prepare_env.os.path.getsize',
return_value=0), \
self.assertRaises(Exception):
- CONST.openstack_creds = 'test_creds'
+ CONST.__setattr__('openstack_creds', 'test_creds')
prepare_env.source_rc_file()
def test_source_rc_missing_installer_ip(self):
with mock.patch('functest.ci.prepare_env.os.path.isfile',
return_value=False), \
self.assertRaises(Exception):
- CONST.INSTALLER_IP = None
- CONST.openstack_creds = 'test_creds'
+ CONST.__setattr__('INSTALLER_IP', None)
+ CONST.__setattr__('openstack_creds', 'test_creds')
prepare_env.source_rc_file()
def test_source_rc_missing_installer_type(self):
with mock.patch('functest.ci.prepare_env.os.path.isfile',
return_value=False), \
self.assertRaises(Exception):
- CONST.INSTALLER_IP = 'test_ip'
- CONST.openstack_creds = 'test_creds'
- CONST.INSTALLER_TYPE = 'test_type'
+ CONST.__setattr__('INSTALLER_IP', 'test_ip')
+ CONST.__setattr__('openstack_creds', 'test_creds')
+ CONST.__setattr__('INSTALLER_TYPE', 'test_type')
opnfv_constants.INSTALLERS = []
prepare_env.source_rc_file()
@@ -259,9 +273,9 @@ class PrepareEnvTesting(unittest.TestCase):
mock.patch('functest.ci.prepare_env.subprocess.Popen') \
as mock_subproc_popen, \
self.assertRaises(Exception):
- CONST.openstack_creds = 'test_creds'
- CONST.INSTALLER_IP = None
- CONST.INSTALLER_TYPE = 'test_type'
+ CONST.__setattr__('openstack_creds', 'test_creds')
+ CONST.__setattr__('INSTALLER_IP', None)
+ CONST.__setattr__('INSTALLER_TYPE', 'test_type')
opnfv_constants.INSTALLERS = ['test_type']
process_mock = mock.Mock()
@@ -281,7 +295,7 @@ class PrepareEnvTesting(unittest.TestCase):
return_value={'tkey1': 'tvalue1'}), \
mock.patch('functest.ci.prepare_env.os.remove') as m, \
mock.patch('functest.ci.prepare_env.yaml.dump'):
- CONST.DEPLOY_SCENARIO = 'test_scenario'
+ CONST.__setattr__('DEPLOY_SCENARIO', 'test_scenario')
prepare_env.patch_file('test_file')
self.assertTrue(m.called)
@@ -321,12 +335,12 @@ class PrepareEnvTesting(unittest.TestCase):
cmd = "rally deployment destroy opnfv-rally"
error_msg = "Deployment %s does not exist." % \
- CONST.rally_deployment_name
+ CONST.__getattribute__('rally_deployment_name')
mock_logger_info.assert_any_call("Creating Rally environment...")
mock_exec.assert_any_call(cmd, error_msg=error_msg, verbose=False)
cmd = "rally deployment create --file=rally_conf.json --name="
- cmd += CONST.rally_deployment_name
+ cmd += CONST.__getattribute__('rally_deployment_name')
error_msg = "Problem while creating Rally deployment"
mock_exec_raise.assert_any_call(cmd, error_msg=error_msg)
@@ -352,7 +366,7 @@ class PrepareEnvTesting(unittest.TestCase):
'stdout.readline.return_value': '0'}
mock_popen.configure_mock(**attrs)
- CONST.tempest_deployment_name = 'test_dep_name'
+ CONST.__setattr__('tempest_deployment_name', 'test_dep_name')
with mock.patch('functest.ci.prepare_env.'
'ft_utils.execute_command_raise',
side_effect=Exception), \
@@ -379,7 +393,7 @@ class PrepareEnvTesting(unittest.TestCase):
with mock.patch('functest.ci.prepare_env.os.path.isfile',
return_value=False), \
self.assertRaises(Exception):
- prepare_env.check_environment()
+ prepare_env.check_environment()
@mock.patch('functest.ci.prepare_env.sys.exit')
@mock.patch('functest.ci.prepare_env.logger.error')
@@ -431,7 +445,8 @@ class PrepareEnvTesting(unittest.TestCase):
self.assertTrue(mock_install_rally.called)
self.assertTrue(mock_install_temp.called)
self.assertTrue(mock_create_flavor.called)
- m.assert_called_once_with(CONST.env_active, "w")
+ m.assert_called_once_with(
+ CONST.__getattribute__('env_active'), "w")
self.assertTrue(mock_check_env.called)
self.assertTrue(mock_print_info.called)
diff --git a/functest/tests/unit/ci/test_run_tests.py b/functest/tests/unit/ci/test_run_tests.py
index 7d02b1af1..d0052392f 100644
--- a/functest/tests/unit/ci/test_run_tests.py
+++ b/functest/tests/unit/ci/test_run_tests.py
@@ -62,24 +62,13 @@ class RunTestsTesting(unittest.TestCase):
@mock.patch('functest.ci.run_tests.os_snapshot.main')
def test_generate_os_snapshot(self, mock_os_snap):
- run_tests.generate_os_snapshot()
- self.assertTrue(mock_os_snap.called)
+ run_tests.generate_os_snapshot()
+ self.assertTrue(mock_os_snap.called)
@mock.patch('functest.ci.run_tests.os_clean.main')
def test_cleanup(self, mock_os_clean):
- run_tests.cleanup()
- self.assertTrue(mock_os_clean.called)
-
- def test_update_test_info(self):
- run_tests.GlobalVariables.EXECUTED_TEST_CASES = [self.test]
- run_tests.update_test_info('test_name',
- 'test_result',
- 'test_duration')
- exp = self.test
- exp.update({"result": 'test_result',
- "duration": 'test_duration'})
- self.assertEqual(run_tests.GlobalVariables.EXECUTED_TEST_CASES,
- [exp])
+ run_tests.cleanup()
+ self.assertTrue(mock_os_clean.called)
def test_get_run_dict_if_defined_default(self):
mock_obj = mock.Mock()
@@ -148,10 +137,8 @@ class RunTestsTesting(unittest.TestCase):
mock.patch('functest.ci.run_tests.source_rc_file'), \
mock.patch('functest.ci.run_tests.generate_os_snapshot'), \
mock.patch('functest.ci.run_tests.cleanup'), \
- mock.patch('functest.ci.run_tests.update_test_info'), \
mock.patch('functest.ci.run_tests.get_run_dict',
return_value=test_run_dict), \
- mock.patch('functest.ci.run_tests.generate_report.main'), \
self.assertRaises(run_tests.BlockingTestFailed) as context:
run_tests.GlobalVariables.CLEAN_FLAG = True
run_tests.run_test(mock_test, 'tier_name')
@@ -176,21 +163,17 @@ class RunTestsTesting(unittest.TestCase):
@mock.patch('functest.ci.run_tests.logger.info')
def test_run_all_default(self, mock_logger_info):
- with mock.patch('functest.ci.run_tests.run_tier') as mock_method, \
- mock.patch('functest.ci.run_tests.generate_report.init'), \
- mock.patch('functest.ci.run_tests.generate_report.main'):
- CONST.CI_LOOP = 'test_ci_loop'
+ with mock.patch('functest.ci.run_tests.run_tier') as mock_method:
+ CONST.__setattr__('CI_LOOP', 'test_ci_loop')
run_tests.run_all(self.tiers)
mock_method.assert_any_call(self.tier)
self.assertTrue(mock_logger_info.called)
@mock.patch('functest.ci.run_tests.logger.info')
- def test_run_all__missing_tier(self, mock_logger_info):
- with mock.patch('functest.ci.run_tests.generate_report.init'), \
- mock.patch('functest.ci.run_tests.generate_report.main'):
- CONST.CI_LOOP = 'loop_re_not_available'
- run_tests.run_all(self.tiers)
- self.assertTrue(mock_logger_info.called)
+ def test_run_all_missing_tier(self, mock_logger_info):
+ CONST.__setattr__('CI_LOOP', 'loop_re_not_available')
+ run_tests.run_all(self.tiers)
+ self.assertTrue(mock_logger_info.called)
def test_main_failed(self):
kwargs = {'test': 'test_name', 'noclean': True, 'report': True}
@@ -221,7 +204,6 @@ class RunTestsTesting(unittest.TestCase):
with mock.patch('functest.ci.run_tests.tb.TierBuilder',
return_value=mock_obj), \
mock.patch('functest.ci.run_tests.source_rc_file'), \
- mock.patch('functest.ci.run_tests.generate_report.init'), \
mock.patch('functest.ci.run_tests.run_tier') as m:
self.assertEqual(run_tests.main(**kwargs),
run_tests.Result.EX_OK)
@@ -234,7 +216,6 @@ class RunTestsTesting(unittest.TestCase):
with mock.patch('functest.ci.run_tests.tb.TierBuilder',
return_value=mock_obj), \
mock.patch('functest.ci.run_tests.source_rc_file'), \
- mock.patch('functest.ci.run_tests.generate_report.init'), \
mock.patch('functest.ci.run_tests.run_test') as m:
self.assertEqual(run_tests.main(**kwargs),
run_tests.Result.EX_OK)
@@ -248,7 +229,6 @@ class RunTestsTesting(unittest.TestCase):
with mock.patch('functest.ci.run_tests.tb.TierBuilder',
return_value=mock_obj), \
mock.patch('functest.ci.run_tests.source_rc_file'), \
- mock.patch('functest.ci.run_tests.generate_report.init'), \
mock.patch('functest.ci.run_tests.run_all') as m:
self.assertEqual(run_tests.main(**kwargs),
run_tests.Result.EX_OK)
@@ -262,11 +242,11 @@ class RunTestsTesting(unittest.TestCase):
with mock.patch('functest.ci.run_tests.tb.TierBuilder',
return_value=mock_obj), \
mock.patch('functest.ci.run_tests.source_rc_file'), \
- mock.patch('functest.ci.run_tests.generate_report.init'), \
mock.patch('functest.ci.run_tests.logger.debug') as m:
self.assertEqual(run_tests.main(**kwargs),
run_tests.Result.EX_ERROR)
self.assertTrue(m.called)
+
if __name__ == "__main__":
unittest.main(verbosity=2)
diff --git a/functest/tests/unit/ci/test_tier_builder.py b/functest/tests/unit/ci/test_tier_builder.py
index 438fa7c25..feaf33a81 100644
--- a/functest/tests/unit/ci/test_tier_builder.py
+++ b/functest/tests/unit/ci/test_tier_builder.py
@@ -22,6 +22,7 @@ class TierBuilderTesting(unittest.TestCase):
'scenario': 'test_scenario'}
self.testcase = {'dependencies': self.dependency,
+ 'enabled': 'true',
'case_name': 'test_name',
'criteria': 'test_criteria',
'blocking': 'test_blocking',
@@ -78,6 +79,13 @@ class TierBuilderTesting(unittest.TestCase):
self.assertEqual(self.tierbuilder.get_tests('test_tier2'),
None)
+ def test_get_tier_name_ok(self):
+ self.assertEqual(self.tierbuilder.get_tier_name('test_name'),
+ 'test_tier')
+
+ def test_get_tier_name_ko(self):
+ self.assertEqual(self.tierbuilder.get_tier_name('test_name2'), None)
+
if __name__ == "__main__":
unittest.main(verbosity=2)
diff --git a/functest/tests/unit/ci/test_tier_handler.py b/functest/tests/unit/ci/test_tier_handler.py
index 21df4098b..280062743 100644
--- a/functest/tests/unit/ci/test_tier_handler.py
+++ b/functest/tests/unit/ci/test_tier_handler.py
@@ -32,6 +32,7 @@ class TierHandlerTesting(unittest.TestCase):
'test_ci_loop',
description='test_desc')
self.testcase = tier_handler.TestCase('test_name',
+ 'true',
self.mock_depend,
'test_criteria',
'test_blocking',
@@ -116,6 +117,10 @@ class TierHandlerTesting(unittest.TestCase):
self.assertEqual(self.tier.get_name(),
'test_tier')
+ def test_testcase_is_enabled(self):
+ self.assertEqual(self.testcase.is_enabled(),
+ 'true')
+
def test_testcase_get_criteria(self):
self.assertEqual(self.tier.get_order(),
'test_order')
diff --git a/functest/tests/unit/cli/commands/test_cli_env.py b/functest/tests/unit/cli/commands/test_cli_env.py
index 4b6ea57a7..c3d89ea3a 100644
--- a/functest/tests/unit/cli/commands/test_cli_env.py
+++ b/functest/tests/unit/cli/commands/test_cli_env.py
@@ -28,7 +28,7 @@ class CliEnvTesting(unittest.TestCase):
@mock.patch('functest.cli.commands.cli_testcase.ft_utils.execute_command')
def test_prepare_default(self, mock_ft_utils, mock_os):
cmd = ("python %s/functest/ci/prepare_env.py start" %
- CONST.dir_repo_functest)
+ CONST.__getattribute__('dir_repo_functest'))
self.cli_environ.prepare()
mock_ft_utils.assert_called_with(cmd)
@@ -40,29 +40,30 @@ class CliEnvTesting(unittest.TestCase):
mock.patch('functest.cli.commands.cli_testcase.os.remove') \
as mock_os_remove:
cmd = ("python %s/functest/ci/prepare_env.py start" %
- CONST.dir_repo_functest)
+ CONST.__getattribute__('dir_repo_functest'))
self.cli_environ.prepare()
- mock_os_remove.assert_called_once_with(CONST.env_active)
+ mock_os_remove.assert_called_once_with(
+ CONST.__getattribute__('env_active'))
mock_ft_utils.assert_called_with(cmd)
def _test_show_missing_env_var(self, var, *args):
if var == 'INSTALLER_TYPE':
- CONST.INSTALLER_TYPE = None
+ CONST.__setattr__('INSTALLER_TYPE', None)
reg_string = "| INSTALLER: Unknown, \S+\s*|"
elif var == 'INSTALLER_IP':
- CONST.INSTALLER_IP = None
+ CONST.__setattr__('INSTALLER_IP', None)
reg_string = "| INSTALLER: \S+, Unknown\s*|"
elif var == 'SCENARIO':
- CONST.DEPLOY_SCENARIO = None
+ CONST.__setattr__('DEPLOY_SCENARIO', None)
reg_string = "| SCENARIO: Unknown\s*|"
elif var == 'NODE':
- CONST.NODE_NAME = None
+ CONST.__setattr__('NODE_NAME', None)
reg_string = "| POD: Unknown\s*|"
elif var == 'BUILD_TAG':
- CONST.BUILD_TAG = None
+ CONST.__setattr__('BUILD_TAG', None)
reg_string = "| BUILD TAG: None|"
elif var == 'DEBUG':
- CONST.CI_DEBUG = None
+ CONST.__setattr__('CI_DEBUG', None)
reg_string = "| DEBUG FLAG: false\s*|"
elif var == 'STATUS':
reg_string = "| STATUS: not ready\s*|"
@@ -106,7 +107,7 @@ class CliEnvTesting(unittest.TestCase):
@mock.patch('functest.cli.commands.cli_env.os.path.exists',
return_value=False)
def test_show_missing_git_repo_dir(self, *args):
- CONST.dir_repo_functest = None
+ CONST.__setattr__('dir_repo_functest', None)
self.assertRaises(NoSuchPathError, lambda: self.cli_environ.show())
@mock.patch('functest.cli.commands.cli_env.click.echo')
diff --git a/functest/tests/unit/cli/commands/test_cli_os.py b/functest/tests/unit/cli/commands/test_cli_os.py
index f0e58c676..540427690 100644
--- a/functest/tests/unit/cli/commands/test_cli_os.py
+++ b/functest/tests/unit/cli/commands/test_cli_os.py
@@ -69,10 +69,10 @@ class CliOpenStackTesting(unittest.TestCase):
def test_fetch_credentials_default(self, mock_click_echo,
mock_os_path,
mock_ftutils_execute):
- CONST.INSTALLER_TYPE = self.installer_type
- CONST.INSTALLER_IP = self.installer_ip
+ CONST.__setattr__('INSTALLER_TYPE', self.installer_type)
+ CONST.__setattr__('INSTALLER_IP', self.installer_ip)
cmd = ("%s/releng/utils/fetch_os_creds.sh -d %s -i %s -a %s"
- % (CONST.dir_repos,
+ % (CONST.__getattribute__('dir_repos'),
self.openstack_creds,
self.installer_type,
self.installer_ip))
@@ -92,15 +92,13 @@ class CliOpenStackTesting(unittest.TestCase):
def test_fetch_credentials_missing_installer_type(self, mock_click_echo,
mock_os_path,
mock_ftutils_execute):
- installer_type = None
- installer_ip = self.installer_ip
- CONST.INSTALLER_TYPE = installer_type
- CONST.INSTALLER_IP = installer_ip
+ CONST.__setattr__('INSTALLER_TYPE', None)
+ CONST.__setattr__('INSTALLER_IP', self.installer_ip)
cmd = ("%s/releng/utils/fetch_os_creds.sh -d %s -i %s -a %s"
- % (CONST.dir_repos,
+ % (CONST.__getattribute__('dir_repos'),
self.openstack_creds,
- installer_type,
- installer_ip))
+ None,
+ self.installer_ip))
self.cli_os.openstack_creds = self.openstack_creds
self.cli_os.fetch_credentials()
mock_click_echo.assert_any_call("The environment variable "
@@ -109,8 +107,8 @@ class CliOpenStackTesting(unittest.TestCase):
mock_click_echo.assert_any_call("Fetching credentials from "
"installer node '%s' with "
"IP=%s.." %
- (installer_type,
- installer_ip))
+ (None,
+ self.installer_ip))
mock_ftutils_execute.assert_called_once_with(cmd, verbose=False)
@mock.patch('functest.cli.commands.cli_os.ft_utils.execute_command')
@@ -122,10 +120,10 @@ class CliOpenStackTesting(unittest.TestCase):
mock_ftutils_execute):
installer_type = self.installer_type
installer_ip = None
- CONST.INSTALLER_TYPE = installer_type
- CONST.INSTALLER_IP = installer_ip
+ CONST.__setattr__('INSTALLER_TYPE', installer_type)
+ CONST.__setattr__('INSTALLER_IP', installer_ip)
cmd = ("%s/releng/utils/fetch_os_creds.sh -d %s -i %s -a %s"
- % (CONST.dir_repos,
+ % (CONST.__getattribute__('dir_repos'),
self.openstack_creds,
installer_type,
installer_ip))
@@ -144,8 +142,9 @@ class CliOpenStackTesting(unittest.TestCase):
@mock.patch('functest.cli.commands.cli_os.ft_utils.execute_command')
def test_check(self, mock_ftutils_execute):
with mock.patch.object(self.cli_os, 'ping_endpoint'):
- CONST.dir_repo_functest = self.dir_repo_functest
- cmd = CONST.dir_repo_functest + "/functest/ci/check_os.sh"
+ CONST.__setattr__('dir_repo_functest', self.dir_repo_functest)
+ cmd = os.path.join(CONST.__getattribute__('dir_repo_functest'),
+ "functest/ci/check_os.sh")
self.cli_os.check()
mock_ftutils_execute.assert_called_once_with(cmd, verbose=False)
diff --git a/functest/tests/unit/cli/commands/test_cli_testcase.py b/functest/tests/unit/cli/commands/test_cli_testcase.py
index 39c8139d7..2d09514ec 100644
--- a/functest/tests/unit/cli/commands/test_cli_testcase.py
+++ b/functest/tests/unit/cli/commands/test_cli_testcase.py
@@ -42,7 +42,9 @@ class CliTestCasesTesting(unittest.TestCase):
@mock.patch('functest.cli.commands.cli_testcase.ft_utils.execute_command')
def test_run_default(self, mock_ft_utils, mock_os):
cmd = ("python %s/functest/ci/run_tests.py "
- "%s -t %s" % (CONST.dir_repo_functest, "-n -r ", self.testname))
+ "%s -t %s" %
+ (CONST.__getattribute__('dir_repo_functest'),
+ "-n -r ", self.testname))
self.cli_tests.run(self.testname, noclean=True, report=True)
mock_ft_utils.assert_called_with(cmd)
@@ -51,7 +53,9 @@ class CliTestCasesTesting(unittest.TestCase):
@mock.patch('functest.cli.commands.cli_testcase.ft_utils.execute_command')
def test_run_noclean_missing_report(self, mock_ft_utils, mock_os):
cmd = ("python %s/functest/ci/run_tests.py "
- "%s -t %s" % (CONST.dir_repo_functest, "-n ", self.testname))
+ "%s -t %s" %
+ (CONST.__getattribute__('dir_repo_functest'),
+ "-n ", self.testname))
self.cli_tests.run(self.testname, noclean=True, report=False)
mock_ft_utils.assert_called_with(cmd)
@@ -60,7 +64,9 @@ class CliTestCasesTesting(unittest.TestCase):
@mock.patch('functest.cli.commands.cli_testcase.ft_utils.execute_command')
def test_run_report_missing_noclean(self, mock_ft_utils, mock_os):
cmd = ("python %s/functest/ci/run_tests.py "
- "%s -t %s" % (CONST.dir_repo_functest, "-r ", self.testname))
+ "%s -t %s" %
+ (CONST.__getattribute__('dir_repo_functest'),
+ "-r ", self.testname))
self.cli_tests.run(self.testname, noclean=False, report=True)
mock_ft_utils.assert_called_with(cmd)
@@ -69,7 +75,9 @@ class CliTestCasesTesting(unittest.TestCase):
@mock.patch('functest.cli.commands.cli_testcase.ft_utils.execute_command')
def test_run_missing_noclean_report(self, mock_ft_utils, mock_os):
cmd = ("python %s/functest/ci/run_tests.py "
- "%s -t %s" % (CONST.dir_repo_functest, "", self.testname))
+ "%s -t %s" %
+ (CONST.__getattribute__('dir_repo_functest'),
+ "", self.testname))
self.cli_tests.run(self.testname, noclean=False, report=False)
mock_ft_utils.assert_called_with(cmd)
diff --git a/functest/tests/unit/cli/commands/test_cli_tier.py b/functest/tests/unit/cli/commands/test_cli_tier.py
index 802359f16..fbc752537 100644
--- a/functest/tests/unit/cli/commands/test_cli_tier.py
+++ b/functest/tests/unit/cli/commands/test_cli_tier.py
@@ -90,8 +90,9 @@ class CliTierTesting(unittest.TestCase):
@mock.patch('functest.cli.commands.cli_tier.ft_utils.execute_command')
def test_run_default(self, mock_ft_utils, mock_os):
cmd = ("python %s/functest/ci/run_tests.py "
- "%s -t %s" % (CONST.dir_repo_functest, "-n -r ",
- self.tiername))
+ "%s -t %s" %
+ (CONST.__getattribute__('dir_repo_functest'),
+ "-n -r ", self.tiername))
self.cli_tier.run(self.tiername, noclean=True, report=True)
mock_ft_utils.assert_called_with(cmd)
@@ -100,8 +101,9 @@ class CliTierTesting(unittest.TestCase):
@mock.patch('functest.cli.commands.cli_tier.ft_utils.execute_command')
def test_run_report_missing_noclean(self, mock_ft_utils, mock_os):
cmd = ("python %s/functest/ci/run_tests.py "
- "%s -t %s" % (CONST.dir_repo_functest, "-r ",
- self.tiername))
+ "%s -t %s" %
+ (CONST.__getattribute__('dir_repo_functest'),
+ "-r ", self.tiername))
self.cli_tier.run(self.tiername, noclean=False, report=True)
mock_ft_utils.assert_called_with(cmd)
@@ -110,8 +112,9 @@ class CliTierTesting(unittest.TestCase):
@mock.patch('functest.cli.commands.cli_tier.ft_utils.execute_command')
def test_run_noclean_missing_report(self, mock_ft_utils, mock_os):
cmd = ("python %s/functest/ci/run_tests.py "
- "%s -t %s" % (CONST.dir_repo_functest, "-n ",
- self.tiername))
+ "%s -t %s" %
+ (CONST.__getattribute__('dir_repo_functest'),
+ "-n ", self.tiername))
self.cli_tier.run(self.tiername, noclean=True, report=False)
mock_ft_utils.assert_called_with(cmd)
@@ -120,8 +123,9 @@ class CliTierTesting(unittest.TestCase):
@mock.patch('functest.cli.commands.cli_tier.ft_utils.execute_command')
def test_run_missing_noclean_report(self, mock_ft_utils, mock_os):
cmd = ("python %s/functest/ci/run_tests.py "
- "%s -t %s" % (CONST.dir_repo_functest, "",
- self.tiername))
+ "%s -t %s" %
+ (CONST.__getattribute__('dir_repo_functest'),
+ "", self.tiername))
self.cli_tier.run(self.tiername, noclean=False, report=False)
mock_ft_utils.assert_called_with(cmd)
diff --git a/functest/tests/unit/core/test_feature.py b/functest/tests/unit/core/test_feature.py
index 993da5a03..8de42ec50 100644
--- a/functest/tests/unit/core/test_feature.py
+++ b/functest/tests/unit/core/test_feature.py
@@ -28,7 +28,7 @@ class FeatureTestingBase(unittest.TestCase):
_project_name = "bar"
_repo = "dir_repo_copper"
_cmd = "cd /home/opnfv/repos/foo/tests && bash run.sh && cd -"
- _output_file = '/home/opnfv/functest/results/bar.log'
+ _output_file = '/home/opnfv/functest/results/foo.log'
feature = None
@mock.patch('time.time', side_effect=[1, 2])
diff --git a/functest/tests/unit/core/test_pytest_suite_runner.py b/functest/tests/unit/core/test_pytest_suite_runner.py
new file mode 100644
index 000000000..15e5bd73b
--- /dev/null
+++ b/functest/tests/unit/core/test_pytest_suite_runner.py
@@ -0,0 +1,51 @@
+#!/usr/bin/env python
+
+# 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
+
+# pylint: disable=missing-docstring
+
+import logging
+import unittest
+
+import mock
+
+from functest.core import pytest_suite_runner
+from functest.core import testcase
+
+
+class PyTestSuiteRunnerTesting(unittest.TestCase):
+
+ logging.disable(logging.CRITICAL)
+
+ def setUp(self):
+ self.psrunner = pytest_suite_runner.PyTestSuiteRunner()
+ self.result = mock.Mock()
+ attrs = {'errors': [('test1', 'error_msg1')],
+ 'failures': [('test2', 'failure_msg1')]}
+ self.result.configure_mock(**attrs)
+
+ self.pass_results = mock.Mock()
+ attrs = {'errors': None,
+ 'failures': None}
+ self.pass_results.configure_mock(**attrs)
+
+ def test_run(self):
+ self.psrunner.case_name = 'test_case_name'
+ with mock.patch('functest.core.pytest_suite_runner.'
+ 'unittest.TextTestRunner.run',
+ return_value=self.result):
+ self.assertEqual(self.psrunner.run(),
+ testcase.TestCase.EX_OK)
+
+ with mock.patch('functest.core.pytest_suite_runner.'
+ 'unittest.TextTestRunner.run',
+ return_value=self.pass_results):
+ self.assertEqual(self.psrunner.run(),
+ testcase.TestCase.EX_OK)
+
+
+if __name__ == "__main__":
+ unittest.main(verbosity=2)
diff --git a/functest/tests/unit/core/test_testcase.py b/functest/tests/unit/core/test_testcase.py
index cc8446d80..2adf4a6dc 100644
--- a/functest/tests/unit/core/test_testcase.py
+++ b/functest/tests/unit/core/test_testcase.py
@@ -7,7 +7,7 @@
# which accompanies this distribution, and is available at
# http://www.apache.org/licenses/LICENSE-2.0
-"""Define the classe required to fully cover testcase."""
+"""Define the class required to fully cover testcase."""
import logging
import unittest
@@ -20,9 +20,8 @@ __author__ = "Cedric Ollivier <cedric.ollivier@orange.com>"
class TestCaseTesting(unittest.TestCase):
-
"""The class testing TestCase."""
- # pylint: disable=missing-docstring
+ # pylint: disable=missing-docstring,too-many-public-methods
logging.disable(logging.CRITICAL)
@@ -116,12 +115,12 @@ class TestCaseTesting(unittest.TestCase):
def test_check_criteria_missing(self):
self.test.criteria = None
- self.assertEqual(self.test.check_result(),
+ self.assertEqual(self.test.is_successful(),
testcase.TestCase.EX_TESTCASE_FAILED)
def test_check_result_missing(self):
self.test.result = None
- self.assertEqual(self.test.check_result(),
+ self.assertEqual(self.test.is_successful(),
testcase.TestCase.EX_TESTCASE_FAILED)
def test_check_result_failed(self):
@@ -129,7 +128,7 @@ class TestCaseTesting(unittest.TestCase):
# It must be removed as soon as TestCase subclasses
# stop setting result = 'PASS' or 'FAIL'.
self.test.result = 'FAIL'
- self.assertEqual(self.test.check_result(),
+ self.assertEqual(self.test.is_successful(),
testcase.TestCase.EX_TESTCASE_FAILED)
def test_check_result_pass(self):
@@ -137,31 +136,93 @@ class TestCaseTesting(unittest.TestCase):
# It must be removed as soon as TestCase subclasses
# stop setting result = 'PASS' or 'FAIL'.
self.test.result = 'PASS'
- self.assertEqual(self.test.check_result(),
+ self.assertEqual(self.test.is_successful(),
testcase.TestCase.EX_OK)
def test_check_result_lt(self):
self.test.result = 50
- self.assertEqual(self.test.check_result(),
+ self.assertEqual(self.test.is_successful(),
testcase.TestCase.EX_TESTCASE_FAILED)
def test_check_result_eq(self):
self.test.result = 100
- self.assertEqual(self.test.check_result(),
+ self.assertEqual(self.test.is_successful(),
testcase.TestCase.EX_OK)
def test_check_result_gt(self):
self.test.criteria = 50
self.test.result = 100
- self.assertEqual(self.test.check_result(),
+ self.assertEqual(self.test.is_successful(),
testcase.TestCase.EX_OK)
def test_check_result_zero(self):
self.test.criteria = 0
self.test.result = 0
- self.assertEqual(self.test.check_result(),
+ self.assertEqual(self.test.is_successful(),
testcase.TestCase.EX_TESTCASE_FAILED)
+ def test_get_duration_start_ko(self):
+ self.test.start_time = None
+ self.assertEqual(self.test.get_duration(), "XX:XX")
+ self.test.start_time = 0
+ self.assertEqual(self.test.get_duration(), "XX:XX")
+
+ def test_get_duration_end_ko(self):
+ self.test.stop_time = None
+ self.assertEqual(self.test.get_duration(), "XX:XX")
+ self.test.stop_time = 0
+ self.assertEqual(self.test.get_duration(), "XX:XX")
+
+ def test_get_invalid_duration(self):
+ self.test.start_time = 2
+ self.test.stop_time = 1
+ self.assertEqual(self.test.get_duration(), "XX:XX")
+
+ def test_get_zero_duration(self):
+ self.test.start_time = 2
+ self.test.stop_time = 2
+ self.assertEqual(self.test.get_duration(), "00:00")
+
+ def test_get_duration(self):
+ self.test.start_time = 1
+ self.test.stop_time = 180
+ self.assertEqual(self.test.get_duration(), "02:59")
+
+ def test_str_project_name_ko(self):
+ self.test.project_name = None
+ self.assertIn("<functest.core.testcase.TestCase object at",
+ str(self.test))
+
+ def test_str_case_name_ko(self):
+ self.test.case_name = None
+ self.assertIn("<functest.core.testcase.TestCase object at",
+ str(self.test))
+
+ def test_str_pass(self):
+ duration = '01:01'
+ with mock.patch.object(self.test, 'get_duration',
+ return_value=duration), \
+ mock.patch.object(self.test, 'is_successful',
+ return_value=testcase.TestCase.EX_OK):
+ message = str(self.test)
+ self.assertIn(self._project_name, message)
+ self.assertIn(self._case_name, message)
+ self.assertIn(duration, message)
+ self.assertIn('PASS', message)
+
+ def test_str_fail(self):
+ duration = '00:59'
+ with mock.patch.object(self.test, 'get_duration',
+ return_value=duration), \
+ mock.patch.object(
+ self.test, 'is_successful',
+ return_value=testcase.TestCase.EX_TESTCASE_FAILED):
+ message = str(self.test)
+ self.assertIn(self._project_name, message)
+ self.assertIn(self._case_name, message)
+ self.assertIn(duration, message)
+ self.assertIn('FAIL', message)
+
if __name__ == "__main__":
unittest.main(verbosity=2)
diff --git a/functest/tests/unit/core/test_vnf.py b/functest/tests/unit/core/test_vnf.py
new file mode 100644
index 000000000..793e95768
--- /dev/null
+++ b/functest/tests/unit/core/test_vnf.py
@@ -0,0 +1,168 @@
+#!/usr/bin/env python
+
+# 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
+
+# pylint: disable=missing-docstring
+
+import logging
+import os
+import unittest
+
+import mock
+
+from functest.core import vnf
+from functest.core import testcase
+
+
+class VnfBaseTesting(unittest.TestCase):
+
+ logging.disable(logging.CRITICAL)
+
+ def setUp(self):
+ self.test = vnf.VnfOnBoarding(
+ project='functest', case_name='aaa')
+ self.test.project = "functest"
+ self.test.start_time = "1"
+ self.test.stop_time = "5"
+ self.test.result = ""
+ self.test.details = {
+ "orchestrator": {"status": "PASS", "result": "", "duration": 20},
+ "vnf": {"status": "PASS", "result": "", "duration": 15},
+ "test_vnf": {"status": "FAIL", "result": "", "duration": 5}}
+ self.test.keystone_client = 'test_client'
+ self.test.tenant_name = 'test_tenant_name'
+
+ def test_execute_deploy_vnf_fail(self):
+ with mock.patch.object(self.test, 'prepare'),\
+ mock.patch.object(self.test, 'deploy_orchestrator',
+ return_value=None), \
+ mock.patch.object(self.test, 'deploy_vnf',
+ side_effect=Exception):
+ self.assertEqual(self.test.execute(),
+ testcase.TestCase.EX_TESTCASE_FAILED)
+
+ def test_execute_test_vnf_fail(self):
+ with mock.patch.object(self.test, 'prepare'),\
+ mock.patch.object(self.test, 'deploy_orchestrator',
+ return_value=None), \
+ mock.patch.object(self.test, 'deploy_vnf'), \
+ mock.patch.object(self.test, 'test_vnf',
+ side_effect=Exception):
+ self.assertEqual(self.test.execute(),
+ testcase.TestCase.EX_TESTCASE_FAILED)
+
+ @mock.patch('functest.core.vnf.os_utils.get_tenant_id',
+ return_value='test_tenant_id')
+ @mock.patch('functest.core.vnf.os_utils.delete_tenant',
+ return_value=True)
+ @mock.patch('functest.core.vnf.os_utils.get_user_id',
+ return_value='test_user_id')
+ @mock.patch('functest.core.vnf.os_utils.delete_user',
+ return_value=True)
+ def test_execute_default(self, *args):
+ with mock.patch.object(self.test, 'prepare'),\
+ mock.patch.object(self.test, 'deploy_orchestrator',
+ return_value=None), \
+ mock.patch.object(self.test, 'deploy_vnf'), \
+ mock.patch.object(self.test, 'test_vnf'), \
+ mock.patch.object(self.test, 'parse_results',
+ return_value='ret_exit_code'), \
+ mock.patch.object(self.test, 'log_results'):
+ self.assertEqual(self.test.execute(),
+ 'ret_exit_code')
+
+ @mock.patch('functest.core.vnf.os_utils.get_credentials')
+ @mock.patch('functest.core.vnf.os_utils.get_keystone_client')
+ @mock.patch('functest.core.vnf.os_utils.get_user_id', return_value='')
+ def test_prepare_missing_userid(self, *args):
+ with self.assertRaises(Exception):
+ self.test.prepare()
+
+ @mock.patch('functest.core.vnf.os_utils.get_credentials')
+ @mock.patch('functest.core.vnf.os_utils.get_keystone_client')
+ @mock.patch('functest.core.vnf.os_utils.get_user_id',
+ return_value='test_roleid')
+ @mock.patch('functest.core.vnf.os_utils.create_tenant',
+ return_value='')
+ def test_prepare_missing_tenantid(self, *args):
+ with self.assertRaises(Exception):
+ self.test.prepare()
+
+ @mock.patch('functest.core.vnf.os_utils.get_credentials')
+ @mock.patch('functest.core.vnf.os_utils.get_keystone_client')
+ @mock.patch('functest.core.vnf.os_utils.get_user_id',
+ return_value='test_roleid')
+ @mock.patch('functest.core.vnf.os_utils.create_tenant',
+ return_value='test_tenantid')
+ @mock.patch('functest.core.vnf.os_utils.get_role_id',
+ return_value='')
+ def test_prepare_missing_roleid(self, *args):
+ with self.assertRaises(Exception):
+ self.test.prepare()
+
+ @mock.patch('functest.core.vnf.os_utils.get_credentials')
+ @mock.patch('functest.core.vnf.os_utils.get_keystone_client')
+ @mock.patch('functest.core.vnf.os_utils.get_user_id',
+ return_value='test_roleid')
+ @mock.patch('functest.core.vnf.os_utils.create_tenant',
+ return_value='test_tenantid')
+ @mock.patch('functest.core.vnf.os_utils.get_role_id',
+ return_value='test_roleid')
+ @mock.patch('functest.core.vnf.os_utils.add_role_user',
+ return_value='')
+ def test_prepare_role_add_failure(self, *args):
+ with self.assertRaises(Exception):
+ self.test.prepare()
+
+ @mock.patch('functest.core.vnf.os_utils.get_credentials')
+ @mock.patch('functest.core.vnf.os_utils.get_keystone_client')
+ @mock.patch('functest.core.vnf.os_utils.get_user_id',
+ return_value='test_roleid')
+ @mock.patch('functest.core.vnf.os_utils.create_tenant',
+ return_value='test_tenantid')
+ @mock.patch('functest.core.vnf.os_utils.get_role_id',
+ return_value='test_roleid')
+ @mock.patch('functest.core.vnf.os_utils.add_role_user')
+ @mock.patch('functest.core.vnf.os_utils.create_user',
+ return_value='')
+ def test_create_user_failure(self, *args):
+ with self.assertRaises(Exception):
+ self.test.prepare()
+
+ def test_log_results_default(self):
+ with mock.patch('functest.core.vnf.'
+ 'ft_utils.logger_test_results') \
+ as mock_method:
+ self.test.log_results()
+ self.assertTrue(mock_method.called)
+
+ def test_step_failures_default(self):
+ with self.assertRaises(Exception):
+ self.test.step_failure("error_msg")
+
+ def test_deploy_vnf_unimplemented(self):
+ with self.assertRaises(Exception) as context:
+ self.test.deploy_vnf()
+ self.assertTrue('VNF not deployed' in context.exception)
+
+ def test_test_vnf_unimplemented(self):
+ with self.assertRaises(Exception) as context:
+ self.test.test_vnf()()
+ self.assertTrue('VNF not tested' in context.exception)
+
+ def test_parse_results_ex_ok(self):
+ self.test.details['test_vnf']['status'] = 'PASS'
+ self.assertEqual(self.test.parse_results(), os.EX_OK)
+
+ def test_parse_results_ex_run_error(self):
+ self.test.details['vnf']['status'] = 'FAIL'
+ self.assertEqual(self.test.parse_results(), os.EX_SOFTWARE)
+
+
+if __name__ == "__main__":
+ unittest.main(verbosity=2)
diff --git a/functest/tests/unit/core/test_vnf_base.py b/functest/tests/unit/core/test_vnf_base.py
deleted file mode 100644
index 540cf610d..000000000
--- a/functest/tests/unit/core/test_vnf_base.py
+++ /dev/null
@@ -1,52 +0,0 @@
-#!/usr/bin/env python
-
-# 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
-
-import logging
-import unittest
-
-from functest.core import vnf_base
-
-
-class VnfBaseTesting(unittest.TestCase):
-
- logging.disable(logging.CRITICAL)
-
- def setUp(self):
- self.test = vnf_base.VnfOnBoardingBase(project='functest',
- case_name='aaa')
- self.test.project = "functest"
- self.test.start_time = "1"
- self.test.stop_time = "5"
- self.test.result = ""
- self.test.details = {"orchestrator": {"status": "PASS",
- "result": "",
- "duration": 20},
- "vnf": {"status": "PASS",
- "result": "",
- "duration": 15},
- "test_vnf": {"status": "FAIL",
- "result": "",
- "duration": 5}}
-
- def test_deploy_vnf_unimplemented(self):
- with self.assertRaises(Exception) as context:
- self.test.deploy_vnf()
- self.assertTrue('VNF not deployed' in context.exception)
-
- def test_test_vnf_unimplemented(self):
- with self.assertRaises(Exception) as context:
- self.test.test_vnf()()
- self.assertTrue('VNF not tested' in context.exception)
-
- def test_parse_results(self):
- self.assertNotEqual(self.test.parse_results(), 0)
-
-
-if __name__ == "__main__":
- unittest.main(verbosity=2)
diff --git a/functest/tests/unit/energy/__init__.py b/functest/tests/unit/energy/__init__.py
new file mode 100644
index 000000000..e69de29bb
--- /dev/null
+++ b/functest/tests/unit/energy/__init__.py
diff --git a/functest/tests/unit/energy/test_functest_energy.py b/functest/tests/unit/energy/test_functest_energy.py
new file mode 100644
index 000000000..ffe044bc2
--- /dev/null
+++ b/functest/tests/unit/energy/test_functest_energy.py
@@ -0,0 +1,277 @@
+#!/usr/bin/env python
+
+# 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
+
+"""Unitary test for energy module."""
+# pylint: disable=unused-argument
+import logging
+import unittest
+
+import mock
+
+from functest.energy.energy import EnergyRecorder
+import functest.energy.energy as energy
+
+
+CASE_NAME = "UNIT_test_CASE"
+STEP_NAME = "UNIT_test_STEP"
+
+logging.disable(logging.CRITICAL)
+
+
+class MockHttpResponse(object): # pylint: disable=too-few-public-methods
+ """Mock response for Energy recorder API."""
+
+ def __init__(self, text, status_code):
+ """Create an instance of MockHttpResponse."""
+ self.text = text
+ self.status_code = status_code
+
+
+RECORDER_OK = MockHttpResponse(
+ '{"environment": "UNIT_TEST",'
+ ' "step": "string",'
+ ' "scenario": "' + CASE_NAME + '"}',
+ 200
+)
+RECORDER_KO = MockHttpResponse(
+ '{"message": "An unhandled API exception occurred (MOCK)"}',
+ 500
+)
+
+
+def config_loader_mock(config_key):
+ """Return mocked config values."""
+ if config_key == "energy_recorder.api_url":
+ return "http://pod-uri:8888"
+ elif config_key == "energy_recorder.api_user":
+ return "user"
+ elif config_key == "energy_recorder.api_password":
+ return "password"
+ else:
+ raise Exception("Config not mocked")
+
+
+def config_loader_mock_no_creds(config_key):
+ """Return mocked config values."""
+ if config_key == "energy_recorder.api_url":
+ return "http://pod-uri:8888"
+ elif config_key == "energy_recorder.api_user":
+ return ""
+ elif config_key == "energy_recorder.api_password":
+ return ""
+ else:
+ raise Exception("Config not mocked:" + config_key)
+
+
+class EnergyRecorderTest(unittest.TestCase):
+ """Energy module unitary test suite."""
+
+ case_name = CASE_NAME
+ request_headers = {'content-type': 'application/json'}
+ returned_value_to_preserve = "value"
+ exception_message_to_preserve = "exception_message"
+
+ @mock.patch('functest.energy.energy.requests.post',
+ return_value=RECORDER_OK)
+ def test_start(self, post_mock=None):
+ """EnergyRecorder.start method (regular case)."""
+ self.test_load_config()
+ self.assertTrue(EnergyRecorder.start(self.case_name))
+ post_mock.assert_called_once_with(
+ EnergyRecorder.energy_recorder_api["uri"],
+ auth=EnergyRecorder.energy_recorder_api["auth"],
+ data=mock.ANY,
+ headers=self.request_headers
+ )
+
+ @mock.patch('functest.energy.energy.requests.post',
+ side_effect=Exception("Internal execution error (MOCK)"))
+ def test_start_error(self, post_mock=None):
+ """EnergyRecorder.start method (error in method)."""
+ self.test_load_config()
+ self.assertFalse(EnergyRecorder.start(self.case_name))
+ post_mock.assert_called_once_with(
+ EnergyRecorder.energy_recorder_api["uri"],
+ auth=EnergyRecorder.energy_recorder_api["auth"],
+ data=mock.ANY,
+ headers=self.request_headers
+ )
+
+ @mock.patch('functest.energy.energy.requests.post',
+ return_value=RECORDER_KO)
+ def test_start_api_error(self, post_mock=None):
+ """EnergyRecorder.start method (API error)."""
+ self.test_load_config()
+ self.assertFalse(EnergyRecorder.start(self.case_name))
+ post_mock.assert_called_once_with(
+ EnergyRecorder.energy_recorder_api["uri"],
+ auth=EnergyRecorder.energy_recorder_api["auth"],
+ data=mock.ANY,
+ headers=self.request_headers
+ )
+
+ @mock.patch('functest.energy.energy.requests.post',
+ return_value=RECORDER_OK)
+ def test_set_step(self, post_mock=None):
+ """EnergyRecorder.set_step method (regular case)."""
+ self.test_load_config()
+ self.assertTrue(EnergyRecorder.set_step(STEP_NAME))
+ post_mock.assert_called_once_with(
+ EnergyRecorder.energy_recorder_api["uri"] + "/step",
+ auth=EnergyRecorder.energy_recorder_api["auth"],
+ data=mock.ANY,
+ headers=self.request_headers
+ )
+
+ @mock.patch('functest.energy.energy.requests.post',
+ return_value=RECORDER_KO)
+ def test_set_step_api_error(self, post_mock=None):
+ """EnergyRecorder.set_step method (API error)."""
+ self.test_load_config()
+ self.assertFalse(EnergyRecorder.set_step(STEP_NAME))
+ post_mock.assert_called_once_with(
+ EnergyRecorder.energy_recorder_api["uri"] + "/step",
+ auth=EnergyRecorder.energy_recorder_api["auth"],
+ data=mock.ANY,
+ headers=self.request_headers
+ )
+
+ @mock.patch('functest.energy.energy.requests.post',
+ side_effect=Exception("Internal execution error (MOCK)"))
+ def test_set_step_error(self, post_mock=None):
+ """EnergyRecorder.set_step method (method error)."""
+ self.test_load_config()
+ self.assertFalse(EnergyRecorder.set_step(STEP_NAME))
+ post_mock.assert_called_once_with(
+ EnergyRecorder.energy_recorder_api["uri"] + "/step",
+ auth=EnergyRecorder.energy_recorder_api["auth"],
+ data=mock.ANY,
+ headers=self.request_headers
+ )
+
+ @mock.patch('functest.energy.energy.requests.delete',
+ return_value=RECORDER_OK)
+ def test_stop(self, delete_mock=None):
+ """EnergyRecorder.stop method (regular case)."""
+ self.test_load_config()
+ self.assertTrue(EnergyRecorder.stop())
+ delete_mock.assert_called_once_with(
+ EnergyRecorder.energy_recorder_api["uri"],
+ auth=EnergyRecorder.energy_recorder_api["auth"],
+ headers=self.request_headers
+ )
+
+ @mock.patch('functest.energy.energy.requests.delete',
+ return_value=RECORDER_KO)
+ def test_stop_api_error(self, delete_mock=None):
+ """EnergyRecorder.stop method (API Error)."""
+ self.test_load_config()
+ self.assertFalse(EnergyRecorder.stop())
+ delete_mock.assert_called_once_with(
+ EnergyRecorder.energy_recorder_api["uri"],
+ auth=EnergyRecorder.energy_recorder_api["auth"],
+ headers=self.request_headers
+ )
+
+ @mock.patch('functest.energy.energy.requests.delete',
+ side_effect=Exception("Internal execution error (MOCK)"))
+ def test_stop_error(self, delete_mock=None):
+ """EnergyRecorder.stop method (method error)."""
+ self.test_load_config()
+ self.assertFalse(EnergyRecorder.stop())
+ delete_mock.assert_called_once_with(
+ EnergyRecorder.energy_recorder_api["uri"],
+ auth=EnergyRecorder.energy_recorder_api["auth"],
+ headers=self.request_headers
+ )
+
+ @energy.enable_recording
+ def __decorated_method(self):
+ """Call with to energy recorder decorators."""
+ return self.returned_value_to_preserve
+
+ @energy.enable_recording
+ def __decorated_method_with_ex(self):
+ """Call with to energy recorder decorators."""
+ raise Exception(self.exception_message_to_preserve)
+
+ @mock.patch("functest.energy.energy.EnergyRecorder")
+ @mock.patch("functest.utils.functest_utils.get_pod_name",
+ return_value="MOCK_POD")
+ @mock.patch("functest.utils.functest_utils.get_functest_config",
+ side_effect=config_loader_mock)
+ def test_decorators(self,
+ loader_mock=None,
+ pod_mock=None,
+ recorder_mock=None):
+ """Test energy module decorators."""
+ self.__decorated_method()
+ calls = [mock.call.start(self.case_name),
+ mock.call.stop()]
+ recorder_mock.assert_has_calls(calls)
+
+ def test_decorator_preserve_return(self):
+ """Test that decorator preserve method returned value."""
+ self.test_load_config()
+ self.assertTrue(
+ self.__decorated_method() == self.returned_value_to_preserve
+ )
+
+ def test_decorator_preserve_ex(self):
+ """Test that decorator preserve method exceptions."""
+ self.test_load_config()
+ with self.assertRaises(Exception) as context:
+ self.__decorated_method_with_ex()
+ self.assertTrue(
+ self.exception_message_to_preserve in context.exception
+ )
+
+ @mock.patch("functest.utils.functest_utils.get_functest_config",
+ side_effect=config_loader_mock)
+ @mock.patch("functest.utils.functest_utils.get_pod_name",
+ return_value="MOCK_POD")
+ def test_load_config(self, loader_mock=None, pod_mock=None):
+ """Test load config."""
+ EnergyRecorder.energy_recorder_api = None
+ EnergyRecorder.load_config()
+ self.assertEquals(
+ EnergyRecorder.energy_recorder_api["auth"],
+ ("user", "password")
+ )
+ self.assertEquals(
+ EnergyRecorder.energy_recorder_api["uri"],
+ "http://pod-uri:8888/recorders/environment/MOCK_POD"
+ )
+
+ @mock.patch("functest.utils.functest_utils.get_functest_config",
+ side_effect=config_loader_mock_no_creds)
+ @mock.patch("functest.utils.functest_utils.get_pod_name",
+ return_value="MOCK_POD")
+ def test_load_config_no_creds(self, loader_mock=None, pod_mock=None):
+ """Test load config without creds."""
+ EnergyRecorder.energy_recorder_api = None
+ EnergyRecorder.load_config()
+ self.assertEquals(EnergyRecorder.energy_recorder_api["auth"], None)
+ self.assertEquals(
+ EnergyRecorder.energy_recorder_api["uri"],
+ "http://pod-uri:8888/recorders/environment/MOCK_POD"
+ )
+
+ @mock.patch("functest.utils.functest_utils.get_functest_config",
+ return_value=None)
+ @mock.patch("functest.utils.functest_utils.get_pod_name",
+ return_value="MOCK_POD")
+ def test_load_config_ex(self, loader_mock=None, pod_mock=None):
+ """Test load config with exception."""
+ with self.assertRaises(AssertionError):
+ EnergyRecorder.energy_recorder_api = None
+ EnergyRecorder.load_config()
+ self.assertEquals(EnergyRecorder.energy_recorder_api, None)
+
+
+if __name__ == "__main__":
+ unittest.main(verbosity=2)
diff --git a/functest/tests/unit/odl/test_odl.py b/functest/tests/unit/odl/test_odl.py
index 54d6da72c..e2778e249 100644
--- a/functest/tests/unit/odl/test_odl.py
+++ b/functest/tests/unit/odl/test_odl.py
@@ -12,14 +12,14 @@
import errno
import logging
import os
-import StringIO
import unittest
from keystoneauth1.exceptions import auth_plugins
import mock
from robot.errors import DataError, RobotError
-from robot.result import testcase as result_testcase
+from robot.result import model
from robot.utils.robottime import timestamp_to_secs
+import six
from functest.core import testcase
from functest.opnfv_tests.sdn.odl import odl
@@ -49,11 +49,9 @@ class ODLVisitorTesting(unittest.TestCase):
'elapsedtime': 1000,
'text': 'Hello, World!',
'critical': True}
- test = result_testcase.TestCase(name=data['name'],
- status=data['status'],
- message=data['text'],
- starttime=data['starttime'],
- endtime=data['endtime'])
+ test = model.TestCase(
+ name=data['name'], status=data['status'], message=data['text'],
+ starttime=data['starttime'], endtime=data['endtime'])
test.parent = mock.Mock()
config = {'name': data['parent'],
'criticality.test_is_critical.return_value': data[
@@ -109,6 +107,9 @@ class ODLParseResultTesting(ODLTesting):
"""The class testing ODLTests.parse_results()."""
# pylint: disable=missing-docstring
+ _config = {'name': 'dummy', 'starttime': '20161216 16:00:00.000',
+ 'endtime': '20161216 16:00:01.000'}
+
@mock.patch('robot.api.ExecutionResult', side_effect=DataError)
def test_raises_exc(self, mock_method):
with self.assertRaises(DataError):
@@ -116,15 +117,13 @@ class ODLParseResultTesting(ODLTesting):
mock_method.assert_called_once_with(
os.path.join(odl.ODLTests.res_dir, 'output.xml'))
- def test_ok(self):
- config = {'name': 'dummy', 'starttime': '20161216 16:00:00.000',
- 'endtime': '20161216 16:00:01.000', 'status': 'PASS'}
+ def _test_result(self, config, result):
suite = mock.Mock()
suite.configure_mock(**config)
with mock.patch('robot.api.ExecutionResult',
return_value=mock.Mock(suite=suite)):
self.test.parse_results()
- self.assertEqual(self.test.result, config['status'])
+ self.assertEqual(self.test.result, result)
self.assertEqual(self.test.start_time,
timestamp_to_secs(config['starttime']))
self.assertEqual(self.test.stop_time,
@@ -132,6 +131,26 @@ class ODLParseResultTesting(ODLTesting):
self.assertEqual(self.test.details,
{'description': config['name'], 'tests': []})
+ def test_null_passed(self):
+ self._config.update({'statistics.critical.passed': 0,
+ 'statistics.critical.total': 20})
+ self._test_result(self._config, 0)
+
+ def test_no_test(self):
+ self._config.update({'statistics.critical.passed': 20,
+ 'statistics.critical.total': 0})
+ self._test_result(self._config, 0)
+
+ def test_half_success(self):
+ self._config.update({'statistics.critical.passed': 10,
+ 'statistics.critical.total': 20})
+ self._test_result(self._config, 50)
+
+ def test_success(self):
+ self._config.update({'statistics.critical.passed': 20,
+ 'statistics.critical.total': 20})
+ self._test_result(self._config, 100)
+
class ODLRobotTesting(ODLTesting):
@@ -152,7 +171,7 @@ class ODLRobotTesting(ODLTesting):
os.path.join(odl.ODLTests.odl_test_repo,
'csit/variables/Variables.py'), inplace=True)
- @mock.patch('sys.stdout', new_callable=StringIO.StringIO)
+ @mock.patch('sys.stdout', new_callable=six.StringIO)
def _test_set_vars(self, msg1, msg2, *args):
line = mock.MagicMock()
line.__iter__.return_value = [msg1]
@@ -170,7 +189,7 @@ class ODLRobotTesting(ODLTesting):
def test_set_vars_auth1(self):
self._test_set_vars("AUTH1 = []", "AUTH1 = []")
- @mock.patch('sys.stdout', new_callable=StringIO.StringIO)
+ @mock.patch('sys.stdout', new_callable=six.StringIO)
def test_set_vars_auth_foo(self, *args):
line = mock.MagicMock()
line.__iter__.return_value = ["AUTH = []"]
@@ -337,9 +356,11 @@ class ODLMainTesting(ODLTesting):
with mock.patch.object(self.test, 'set_robotframework_vars',
return_value=True), \
mock.patch.object(odl, 'open', mock.mock_open(),
- create=True), \
+ create=True) as mock_open, \
mock.patch.object(self.test, 'parse_results'):
self._test_main(testcase.TestCase.EX_OK, *args)
+ mock_open.assert_called_once_with(
+ os.path.join(odl.ODLTests.res_dir, 'stdout.txt'), 'w+')
@mock.patch('os.remove')
@mock.patch('robot.run', return_value=1)
@@ -348,9 +369,11 @@ class ODLMainTesting(ODLTesting):
with mock.patch.object(self.test, 'set_robotframework_vars',
return_value=True), \
mock.patch.object(odl, 'open', mock.mock_open(),
- create=True), \
+ create=True) as mock_open, \
mock.patch.object(self.test, 'parse_results'):
self._test_main(testcase.TestCase.EX_OK, *args)
+ mock_open.assert_called_once_with(
+ os.path.join(odl.ODLTests.res_dir, 'stdout.txt'), 'w+')
@mock.patch('os.remove', side_effect=OSError)
@mock.patch('robot.run')
@@ -359,9 +382,11 @@ class ODLMainTesting(ODLTesting):
with mock.patch.object(self.test, 'set_robotframework_vars',
return_value=True), \
mock.patch.object(odl, 'open', mock.mock_open(),
- create=True), \
+ create=True) as mock_open, \
mock.patch.object(self.test, 'parse_results'):
self._test_main(testcase.TestCase.EX_OK, *args)
+ mock_open.assert_called_once_with(
+ os.path.join(odl.ODLTests.res_dir, 'stdout.txt'), 'w+')
class ODLRunTesting(ODLTesting):
@@ -552,7 +577,7 @@ class ODLArgParserTesting(ODLTesting):
"--odlip={}".format(self._sdn_controller_ip)]),
self.defaultargs)
- @mock.patch('sys.stderr', new_callable=StringIO.StringIO)
+ @mock.patch('sys.stderr', new_callable=six.StringIO)
def test_fail(self, mock_method):
self.defaultargs['foo'] = 'bar'
with self.assertRaises(SystemExit):
diff --git a/functest/tests/unit/openstack/rally/test_rally.py b/functest/tests/unit/openstack/rally/test_rally.py
index fe25dfcf9..c78286186 100644
--- a/functest/tests/unit/openstack/rally/test_rally.py
+++ b/functest/tests/unit/openstack/rally/test_rally.py
@@ -343,19 +343,6 @@ class OSRallyTesting(unittest.TestCase):
self.rally_base._run_tests()
self.rally_base._run_task.assert_any_call('test1')
- @mock.patch('functest.opnfv_tests.openstack.rally.rally.logger.info')
- def test_generate_report(self, mock_logger_info):
- summary = [{'test_name': 'test_name',
- 'overall_duration': 5,
- 'nb_tests': 3,
- 'success': 5}]
- self.rally_base.summary = summary
- with mock.patch('functest.opnfv_tests.openstack.rally.rally.'
- 'ft_utils.check_success_rate',
- return_value='criteria'):
- self.rally_base._generate_report()
- self.assertTrue(mock_logger_info.called)
-
def test_clean_up_default(self):
self.rally_base.volume_type = mock.Mock()
self.rally_base.cinder_client = mock.Mock()
diff --git a/functest/tests/unit/openstack/tempest/test_tempest.py b/functest/tests/unit/openstack/tempest/test_tempest.py
index e05e5dfac..bb75c9ed7 100644
--- a/functest/tests/unit/openstack/tempest/test_tempest.py
+++ b/functest/tests/unit/openstack/tempest/test_tempest.py
@@ -151,24 +151,6 @@ class OSTempestTesting(unittest.TestCase):
assert_any_call("Starting Tempest test suite: '%s'."
% cmd_line)
- @mock.patch('functest.opnfv_tests.openstack.tempest.tempest.logger.info')
- def test_parse_verifier_result_default(self, mock_logger_info):
- self.tempestcommon.VERIFICATION_ID = 'test_uuid'
- self.tempestcommon.case_name = 'test_case_name'
- stdout = ['Testscount||2', 'Success||2', 'Skipped||0', 'Failures||0']
- with mock.patch('functest.opnfv_tests.openstack.tempest.tempest.'
- 'subprocess.Popen') as mock_popen, \
- mock.patch('functest.opnfv_tests.openstack.tempest.tempest.'
- 'ft_utils.check_success_rate') as mock_method, \
- mock.patch('__builtin__.open', mock.mock_open()):
- mock_stdout = mock.Mock()
- attrs = {'stdout': stdout}
- mock_stdout.configure_mock(**attrs)
- mock_popen.return_value = mock_stdout
-
- self.tempestcommon.parse_verifier_result()
- mock_method.assert_any_call('test_case_name', 100)
-
@mock.patch('functest.opnfv_tests.openstack.tempest.tempest.'
'os.path.exists', return_value=False)
@mock.patch('functest.opnfv_tests.openstack.tempest.tempest.os.makedirs',
diff --git a/functest/tests/unit/utils/test_decorators.py b/functest/tests/unit/utils/test_decorators.py
new file mode 100644
index 000000000..f8bd9a54f
--- /dev/null
+++ b/functest/tests/unit/utils/test_decorators.py
@@ -0,0 +1,135 @@
+#!/usr/bin/env python
+
+# Copyright (c) 2017 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
+
+"""Define the class required to fully cover decorators."""
+
+from datetime import datetime
+import errno
+import json
+import logging
+import os
+import unittest
+
+import mock
+
+from functest.utils import decorators
+from functest.utils import functest_utils
+
+__author__ = "Cedric Ollivier <cedric.ollivier@orange.com>"
+
+VERSION = 'master'
+DIR = '/dev'
+FILE = '{}/null'.format(DIR)
+URL = 'file://{}'.format(FILE)
+
+
+class DecoratorsTesting(unittest.TestCase):
+ # pylint: disable=missing-docstring
+
+ logging.disable(logging.CRITICAL)
+
+ _case_name = 'base'
+ _project_name = 'functest'
+ _start_time = 1.0
+ _stop_time = 2.0
+ _result = 'PASS'
+ _build_tag = VERSION
+ _node_name = 'bar'
+ _deploy_scenario = 'foo'
+ _installer_type = 'debian'
+
+ def setUp(self):
+ os.environ['INSTALLER_TYPE'] = self._installer_type
+ os.environ['DEPLOY_SCENARIO'] = self._deploy_scenario
+ os.environ['NODE_NAME'] = self._node_name
+ os.environ['BUILD_TAG'] = self._build_tag
+
+ def test_wraps(self):
+ self.assertEqual(functest_utils.push_results_to_db.__name__,
+ "push_results_to_db")
+
+ def _get_json(self):
+ stop_time = datetime.fromtimestamp(self._stop_time).strftime(
+ '%Y-%m-%d %H:%M:%S')
+ start_time = datetime.fromtimestamp(self._start_time).strftime(
+ '%Y-%m-%d %H:%M:%S')
+ data = {'project_name': self._project_name,
+ 'stop_date': stop_time, 'start_date': start_time,
+ 'case_name': self._case_name, 'build_tag': self._build_tag,
+ 'pod_name': self._node_name, 'installer': self._installer_type,
+ 'scenario': self._deploy_scenario, 'version': VERSION,
+ 'details': {}, 'criteria': self._result}
+ return json.dumps(data)
+
+ @mock.patch('{}.get_db_url'.format(functest_utils.__name__),
+ return_value='http://127.0.0.1')
+ @mock.patch('{}.get_version'.format(functest_utils.__name__),
+ return_value=VERSION)
+ @mock.patch('requests.post')
+ def test_http_shema(self, *args):
+ self.assertTrue(functest_utils.push_results_to_db(
+ self._project_name, self._case_name, self._start_time,
+ self._stop_time, self._result, {}))
+ args[1].assert_called_once_with()
+ args[2].assert_called_once_with()
+ args[0].assert_called_once_with(
+ 'http://127.0.0.1', data=self._get_json(),
+ headers={'Content-Type': 'application/json'})
+
+ @mock.patch('{}.get_db_url'.format(functest_utils.__name__),
+ return_value="/dev/null")
+ def test_wrong_shema(self, mock_method=None):
+ self.assertFalse(functest_utils.push_results_to_db(
+ self._project_name, self._case_name, self._start_time,
+ self._stop_time, self._result, {}))
+ mock_method.assert_called_once_with()
+
+ @mock.patch('{}.get_version'.format(functest_utils.__name__),
+ return_value=VERSION)
+ @mock.patch('{}.get_db_url'.format(functest_utils.__name__),
+ return_value=URL)
+ def _test_dump(self, *args):
+ with mock.patch.object(decorators, 'open', mock.mock_open(),
+ create=True) as mock_open:
+ self.assertTrue(functest_utils.push_results_to_db(
+ self._project_name, self._case_name, self._start_time,
+ self._stop_time, self._result, {}))
+ mock_open.assert_called_once_with(FILE, 'a')
+ handle = mock_open()
+ call_args, _ = handle.write.call_args
+ self.assertIn('POST', call_args[0])
+ self.assertIn(self._get_json(), call_args[0])
+ args[0].assert_called_once_with()
+ args[1].assert_called_once_with()
+
+ @mock.patch('os.makedirs')
+ def test_default_dump(self, mock_method=None):
+ self._test_dump()
+ mock_method.assert_called_once_with(DIR)
+
+ @mock.patch('os.makedirs', side_effect=OSError(errno.EEXIST, ''))
+ def test_makedirs_dir_exists(self, mock_method=None):
+ self._test_dump()
+ mock_method.assert_called_once_with(DIR)
+
+ @mock.patch('{}.get_db_url'.format(functest_utils.__name__),
+ return_value=URL)
+ @mock.patch('os.makedirs', side_effect=OSError)
+ def test_makedirs_exc(self, *args):
+ self.assertFalse(
+ functest_utils.push_results_to_db(
+ self._project_name, self._case_name, self._start_time,
+ self._stop_time, self._result, {}))
+ args[0].assert_called_once_with(DIR)
+ args[1].assert_called_once_with()
+
+
+if __name__ == "__main__":
+ logging.basicConfig()
+ unittest.main(verbosity=2)
diff --git a/functest/tests/unit/utils/test_functest_logger.py b/functest/tests/unit/utils/test_functest_logger.py
deleted file mode 100644
index 42e41a141..000000000
--- a/functest/tests/unit/utils/test_functest_logger.py
+++ /dev/null
@@ -1,48 +0,0 @@
-#!/usr/bin/env python
-
-# 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 logging
-import unittest
-
-import mock
-
-from functest.utils import functest_logger
-from functest.utils.constants import CONST
-
-
-class OSUtilsLogger(unittest.TestCase):
-
- logging.disable(logging.CRITICAL)
-
- def setUp(self):
- with mock.patch('__builtin__.open', mock.mock_open()):
- with mock.patch('functest.utils.functest_logger.os.path.exists',
- return_value=True), \
- mock.patch('functest.utils.functest_logger.'
- 'json.load'), \
- mock.patch('functest.utils.functest_logger.'
- 'logging.config.dictConfig') as m:
- self.logger = functest_logger.Logger('os_utils')
- self.assertTrue(m.called)
- with mock.patch('functest.utils.functest_logger.os.path.exists',
- return_value=False), \
- mock.patch('functest.utils.functest_logger.'
- 'logging.basicConfig') as m:
- self.logger = functest_logger.Logger('os_utils')
- self.assertTrue(m.called)
-
- def test_is_debug_false(self):
- CONST.CI_DEBUG = False
- self.assertFalse(self.logger.is_debug())
-
- def test_is_debug_true(self):
- CONST.CI_DEBUG = "True"
- self.assertTrue(self.logger.is_debug())
-
-
-if __name__ == "__main__":
- unittest.main(verbosity=2)
diff --git a/functest/tests/unit/utils/test_functest_utils.py b/functest/tests/unit/utils/test_functest_utils.py
index 573fcb70f..57e0c465d 100644
--- a/functest/tests/unit/utils/test_functest_utils.py
+++ b/functest/tests/unit/utils/test_functest_utils.py
@@ -11,11 +11,11 @@ import logging
import os
import time
import unittest
-import urllib2
from git.exc import NoSuchPathError
import mock
import requests
+from six.moves import urllib
from functest.tests.unit import test_utils
from functest.utils import functest_utils
@@ -62,31 +62,31 @@ class FunctestUtilsTesting(unittest.TestCase):
self.file_yaml = {'general': {'openstack': {'image_name':
'test_image_name'}}}
- @mock.patch('urllib2.urlopen',
- side_effect=urllib2.URLError('no host given'))
+ @mock.patch('six.moves.urllib.request.urlopen',
+ side_effect=urllib.error.URLError('no host given'))
def test_check_internet_connectivity_failed(self, mock_method):
self.assertFalse(functest_utils.check_internet_connectivity())
mock_method.assert_called_once_with(self.url, timeout=self.timeout)
- @mock.patch('urllib2.urlopen')
+ @mock.patch('six.moves.urllib.request.urlopen')
def test_check_internet_connectivity_default(self, mock_method):
self.assertTrue(functest_utils.check_internet_connectivity())
mock_method.assert_called_once_with(self.url, timeout=self.timeout)
- @mock.patch('urllib2.urlopen')
+ @mock.patch('six.moves.urllib.request.urlopen')
def test_check_internet_connectivity_debian(self, mock_method):
self.url = "https://www.debian.org/"
self.assertTrue(functest_utils.check_internet_connectivity(self.url))
mock_method.assert_called_once_with(self.url, timeout=self.timeout)
- @mock.patch('urllib2.urlopen',
- side_effect=urllib2.URLError('no host given'))
+ @mock.patch('six.moves.urllib.request.urlopen',
+ side_effect=urllib.error.URLError('no host given'))
def test_download_url_failed(self, mock_url):
self.assertFalse(functest_utils.download_url(self.url, self.dest_path))
- @mock.patch('urllib2.urlopen')
+ @mock.patch('six.moves.urllib.request.urlopen')
def test_download_url_default(self, mock_url):
- with mock.patch("__builtin__.open", mock.mock_open()) as m, \
+ with mock.patch("six.moves.builtins.open", mock.mock_open()) as m, \
mock.patch('functest.utils.functest_utils.shutil.copyfileobj')\
as mock_sh:
name = self.url.rsplit('/')[-1]
@@ -371,7 +371,7 @@ class FunctestUtilsTesting(unittest.TestCase):
attrs = {'readline.side_effect': self.readline_side}
m.configure_mock(**attrs)
- with mock.patch("__builtin__.open") as mo:
+ with mock.patch("six.moves.builtins.open") as mo:
mo.return_value = m
self.assertEqual(functest_utils.get_resolvconf_ns(),
self.test_ip[1:])
@@ -399,7 +399,8 @@ class FunctestUtilsTesting(unittest.TestCase):
mock_logger_error):
with mock.patch('functest.utils.functest_utils.subprocess.Popen') \
as mock_subproc_open, \
- mock.patch('__builtin__.open', mock.mock_open()) as mopen:
+ mock.patch('six.moves.builtins.open',
+ mock.mock_open()) as mopen:
FunctestUtilsTesting.readline = 0
@@ -428,7 +429,8 @@ class FunctestUtilsTesting(unittest.TestCase):
):
with mock.patch('functest.utils.functest_utils.subprocess.Popen') \
as mock_subproc_open, \
- mock.patch('__builtin__.open', mock.mock_open()) as mopen:
+ mock.patch('six.moves.builtins.open',
+ mock.mock_open()) as mopen:
FunctestUtilsTesting.readline = 0
@@ -503,7 +505,7 @@ class FunctestUtilsTesting(unittest.TestCase):
@mock.patch('functest.utils.functest_utils.logger.error')
def test_get_dict_by_test(self, mock_logger_error):
- with mock.patch('__builtin__.open', mock.mock_open()), \
+ with mock.patch('six.moves.builtins.open', mock.mock_open()), \
mock.patch('functest.utils.functest_utils.yaml.safe_load') \
as mock_yaml, \
mock.patch('functest.utils.functest_utils.get_testcases_'
@@ -531,7 +533,7 @@ class FunctestUtilsTesting(unittest.TestCase):
def test_get_parameter_from_yaml_failed(self):
self.file_yaml['general'] = None
- with mock.patch('__builtin__.open', mock.mock_open()), \
+ with mock.patch('six.moves.builtins.open', mock.mock_open()), \
mock.patch('functest.utils.functest_utils.yaml.safe_load') \
as mock_yaml, \
self.assertRaises(ValueError) as excep:
@@ -543,7 +545,7 @@ class FunctestUtilsTesting(unittest.TestCase):
self.parameter) in excep.exception)
def test_get_parameter_from_yaml_default(self):
- with mock.patch('__builtin__.open', mock.mock_open()), \
+ with mock.patch('six.moves.builtins.open', mock.mock_open()), \
mock.patch('functest.utils.functest_utils.yaml.safe_load') \
as mock_yaml:
mock_yaml.return_value = self.file_yaml
@@ -561,22 +563,6 @@ class FunctestUtilsTesting(unittest.TestCase):
assert_called_once_with(self.parameter,
self.config_yaml)
- def test_check_success_rate_default(self):
- with mock.patch('functest.utils.functest_utils.get_criteria_by_test') \
- as mock_criteria:
- mock_criteria.return_value = self.criteria
- resp = functest_utils.check_success_rate(self.case_name,
- self.result)
- self.assertEqual(resp, 'PASS')
-
- def test_check_success_rate_failed(self):
- with mock.patch('functest.utils.functest_utils.get_criteria_by_test') \
- as mock_criteria:
- mock_criteria.return_value = self.criteria
- resp = functest_utils.check_success_rate(self.case_name,
- 0)
- self.assertEqual(resp, 'FAIL')
-
# TODO: merge_dicts
def test_get_testcases_file_dir(self):
@@ -586,7 +572,7 @@ class FunctestUtilsTesting(unittest.TestCase):
"functest/ci/testcases.yaml")
def test_get_functest_yaml(self):
- with mock.patch('__builtin__.open', mock.mock_open()), \
+ with mock.patch('six.moves.builtins.open', mock.mock_open()), \
mock.patch('functest.utils.functest_utils.yaml.safe_load') \
as mock_yaml:
mock_yaml.return_value = self.file_yaml
diff --git a/functest/tests/unit/utils/test_openstack_utils.py b/functest/tests/unit/utils/test_openstack_utils.py
index 7f3995d03..a7df264c9 100644
--- a/functest/tests/unit/utils/test_openstack_utils.py
+++ b/functest/tests/unit/utils/test_openstack_utils.py
@@ -418,21 +418,45 @@ class OSUtilsTesting(unittest.TestCase):
mock_logger_info.assert_called_once_with("OS_IDENTITY_API_VERSION is "
"set in env as '%s'", '3')
- def test_get_keystone_client(self):
+ @mock.patch('functest.utils.openstack_utils.get_session')
+ @mock.patch('functest.utils.openstack_utils.keystoneclient.Client')
+ @mock.patch('functest.utils.openstack_utils.get_keystone_client_version',
+ return_value='3')
+ @mock.patch('functest.utils.openstack_utils.os.getenv',
+ return_value='public')
+ def test_get_keystone_client_with_interface(self, mock_os_getenv,
+ mock_keystoneclient_version,
+ mock_key_client,
+ mock_get_session):
mock_keystone_obj = mock.Mock()
mock_session_obj = mock.Mock()
- with mock.patch('functest.utils.openstack_utils'
- '.get_keystone_client_version', return_value='3'), \
- mock.patch('functest.utils.openstack_utils'
- '.keystoneclient.Client',
- return_value=mock_keystone_obj) \
- as mock_key_client, \
- mock.patch('functest.utils.openstack_utils.get_session',
- return_value=mock_session_obj):
- self.assertEqual(openstack_utils.get_keystone_client(),
- mock_keystone_obj)
- mock_key_client.assert_called_once_with('3',
- session=mock_session_obj)
+ mock_key_client.return_value = mock_keystone_obj
+ mock_get_session.return_value = mock_session_obj
+ self.assertEqual(openstack_utils.get_keystone_client(),
+ mock_keystone_obj)
+ mock_key_client.assert_called_once_with('3',
+ session=mock_session_obj,
+ interface='public')
+
+ @mock.patch('functest.utils.openstack_utils.get_session')
+ @mock.patch('functest.utils.openstack_utils.keystoneclient.Client')
+ @mock.patch('functest.utils.openstack_utils.get_keystone_client_version',
+ return_value='3')
+ @mock.patch('functest.utils.openstack_utils.os.getenv',
+ return_value='admin')
+ def test_get_keystone_client_no_interface(self, mock_os_getenv,
+ mock_keystoneclient_version,
+ mock_key_client,
+ mock_get_session):
+ mock_keystone_obj = mock.Mock()
+ mock_session_obj = mock.Mock()
+ mock_key_client.return_value = mock_keystone_obj
+ mock_get_session.return_value = mock_session_obj
+ self.assertEqual(openstack_utils.get_keystone_client(),
+ mock_keystone_obj)
+ mock_key_client.assert_called_once_with('3',
+ session=mock_session_obj,
+ interface='admin')
@mock.patch('functest.utils.openstack_utils.os.getenv',
return_value=None)
diff --git a/functest/utils/config.py b/functest/utils/config.py
index b5b845010..d91f63ac2 100755..100644
--- a/functest/utils/config.py
+++ b/functest/utils/config.py
@@ -1,8 +1,11 @@
-import os
+#!/usr/bin/env python
+import os
import yaml
-import env
+import six
+
+from functest.utils import env
class Config(object):
@@ -16,7 +19,7 @@ class Config(object):
self._set_others()
def _parse(self, attr_now, left_parametes):
- for param_n, param_v in left_parametes.iteritems():
+ for param_n, param_v in six.iteritems(left_parametes):
attr_further = self._get_attr_further(attr_now, param_n)
if attr_further:
self.__setattr__(attr_further, param_v)
@@ -32,8 +35,3 @@ class Config(object):
CONF = Config()
-
-if __name__ == "__main__":
- print CONF.vnf_cloudify_ims
- print CONF.vnf_cloudify_ims_tenant_images
- print CONF.vnf_cloudify_ims_tenant_images_centos_7
diff --git a/functest/utils/constants.py b/functest/utils/constants.py
index 2e8eb3f44..75c97c765 100755..100644
--- a/functest/utils/constants.py
+++ b/functest/utils/constants.py
@@ -1,20 +1,17 @@
-import config
-import env
+#!/usr/bin/env python
+
+import six
+
+from functest.utils import config
+from functest.utils import env
class Constants(object):
def __init__(self):
- for attr_n, attr_v in config.CONF.__dict__.iteritems():
+ for attr_n, attr_v in six.iteritems(config.CONF.__dict__):
self.__setattr__(attr_n, attr_v)
- for env_n, env_v in env.ENV.__dict__.iteritems():
+ for env_n, env_v in six.iteritems(env.ENV.__dict__):
self.__setattr__(env_n, env_v)
CONST = Constants()
-
-if __name__ == '__main__':
- print CONST.__dict__
- print CONST.NODE_NAME
- print CONST.vIMS_clearwater_blueprint_url
- print CONST.vIMS_clearwater_blueprint_file_name
- print CONST.vIMS_clearwater_blueprint_name
diff --git a/functest/utils/decorators.py b/functest/utils/decorators.py
index 46ffe35d1..73e0a3520 100644
--- a/functest/utils/decorators.py
+++ b/functest/utils/decorators.py
@@ -3,18 +3,19 @@
# pylint: disable=missing-docstring
import errno
+import functools
import os
-import urlparse
import mock
import requests.sessions
+from six.moves import urllib
def can_dump_request_to_file(method):
def dump_preparedrequest(request, **kwargs):
# pylint: disable=unused-argument
- parseresult = urlparse.urlparse(request.url)
+ parseresult = urllib.parse.urlparse(request.url)
if parseresult.scheme == "file":
try:
dirname = os.path.dirname(parseresult.path)
@@ -33,7 +34,7 @@ def can_dump_request_to_file(method):
def patch_request(method, url, **kwargs):
with requests.sessions.Session() as session:
- parseresult = urlparse.urlparse(url)
+ parseresult = urllib.parse.urlparse(url)
if parseresult.scheme == "file":
with mock.patch.object(session, 'send',
side_effect=dump_preparedrequest):
@@ -41,6 +42,7 @@ def can_dump_request_to_file(method):
else:
return session.request(method=method, url=url, **kwargs)
+ @functools.wraps(method)
def hook(*args, **kwargs):
with mock.patch('requests.api.request', side_effect=patch_request):
return method(*args, **kwargs)
diff --git a/functest/utils/env.py b/functest/utils/env.py
index 7e4df2ea5..c9629e153 100644
--- a/functest/utils/env.py
+++ b/functest/utils/env.py
@@ -1,6 +1,11 @@
+#!/usr/bin/env python
+
import os
import re
+import six
+
+
default_envs = {
'NODE_NAME': 'unknown_pod',
'CI_DEBUG': 'false',
@@ -17,9 +22,9 @@ default_envs = {
class Environment(object):
def __init__(self):
- for k, v in os.environ.iteritems():
+ for k, v in six.iteritems(os.environ):
self.__setattr__(k, v)
- for k, v in default_envs.iteritems():
+ for k, v in six.iteritems(default_envs):
if k not in os.environ:
self.__setattr__(k, v)
self._set_ci_run()
diff --git a/functest/utils/functest_logger.py b/functest/utils/functest_logger.py
deleted file mode 100644
index ba52829f7..000000000
--- a/functest/utils/functest_logger.py
+++ /dev/null
@@ -1,83 +0,0 @@
-#!/usr/bin/env python
-#
-# jose.lausuch@ericsson.com
-# All rights reserved. This program and the accompanying materials
-# are made available under the terms of the Apache License, Version 2.0
-# which accompanies this distribution, and is available at
-# http://www.apache.org/licenses/LICENSE-2.0
-#
-# 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 logging.config
-import os
-
-import json
-
-from functest.utils.constants import CONST
-
-ignore = ["paramiko",
- "stevedore.extension",
- "keystoneauth.session",
- "keystoneauth.identity.v3.base",
- "novaclient.v2.client",
- "neutronclient.v2_0.client",
- "glanceclient.common.http",
- "cinderclient.v2.client",
- "cinderclient.client"]
-
-
-class Logger(object):
-
- instance = None
-
- def __new__(cls, logger_name):
- if cls.instance is None:
- cls.instance = object.__new__(cls)
- return cls.instance
-
- def __init__(self, logger_name):
- self.setup_logging()
- self.logger = logging.getLogger(logger_name)
- for module_name in ignore:
- logging.getLogger(module_name).setLevel(logging.WARNING)
-
- def getLogger(self):
- return self.logger
-
- def is_debug(self):
- if CONST.CI_DEBUG and CONST.CI_DEBUG.lower() == "true":
- return True
- return False
-
- def setup_logging(self, default_path=CONST.dir_functest_logging_cfg,
- default_level=logging.INFO,
- env_key='LOG_CFG'):
- path = default_path
- value = os.getenv(env_key, None)
- if value:
- path = value
- if os.path.exists(path):
- with open(path, 'rt') as f:
- config = json.load(f)
- if (config['handlers'] and
- config['handlers']['console']):
- stream_level = logging.INFO
- if self.is_debug():
- stream_level = logging.DEBUG
- config['handlers']['console']['level'] = stream_level
- logging.config.dictConfig(config)
- else:
- logging.basicConfig(level=default_level)
diff --git a/functest/utils/functest_utils.py b/functest/utils/functest_utils.py
index 7d993cbfc..bf30f56ee 100644
--- a/functest/utils/functest_utils.py
+++ b/functest/utils/functest_utils.py
@@ -9,24 +9,24 @@
#
import functools
import json
+import logging
import os
import re
import shutil
import subprocess
import sys
import time
-import urllib2
from datetime import datetime as dt
import dns.resolver
import requests
+from six.moves import urllib
import yaml
from git import Repo
from functest.utils import decorators
-import functest.utils.functest_logger as ft_logger
-logger = ft_logger.Logger("functest_utils").getLogger()
+logger = logging.getLogger(__name__)
# ----------------------------------------------------------
@@ -39,9 +39,9 @@ def check_internet_connectivity(url='http://www.opnfv.org/'):
Check if there is access to the internet
"""
try:
- urllib2.urlopen(url, timeout=5)
+ urllib.request.urlopen(url, timeout=5)
return True
- except urllib2.URLError:
+ except urllib.error.URLError:
return False
@@ -52,8 +52,8 @@ def download_url(url, dest_path):
name = url.rsplit('/')[-1]
dest = dest_path + "/" + name
try:
- response = urllib2.urlopen(url)
- except (urllib2.HTTPError, urllib2.URLError):
+ response = urllib.request.urlopen(url)
+ except (urllib.error.HTTPError, urllib.error.URLError):
return False
with open(dest, 'wb') as f:
@@ -318,7 +318,7 @@ def execute_command(cmd, info=False, error_msg="",
f.write(line)
else:
line = line.replace('\n', '')
- print line
+ print(line)
sys.stdout.flush()
if output_file:
f.close()
@@ -379,16 +379,6 @@ def get_functest_config(parameter):
return get_parameter_from_yaml(parameter, yaml_)
-def check_success_rate(case_name, result):
- # It should be removed as TestCase tests criteria
- # and result.
- logger.warning('check_success_rate will be removed soon')
- criteria = get_criteria_by_test(case_name)
- if type(criteria) == int and result >= criteria:
- return 'PASS'
- return 'FAIL'
-
-
def merge_dicts(dict1, dict2):
for k in set(dict1.keys()).union(dict2.keys()):
if k in dict1 and k in dict2:
diff --git a/functest/utils/openstack/cinder.py b/functest/utils/openstack/cinder.py
deleted file mode 100644
index f966468a3..000000000
--- a/functest/utils/openstack/cinder.py
+++ /dev/null
@@ -1,7 +0,0 @@
-#!/usr/bin/env python
-#
-# 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
-#
diff --git a/functest/utils/openstack/glance.py b/functest/utils/openstack/glance.py
deleted file mode 100644
index f966468a3..000000000
--- a/functest/utils/openstack/glance.py
+++ /dev/null
@@ -1,7 +0,0 @@
-#!/usr/bin/env python
-#
-# 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
-#
diff --git a/functest/utils/openstack/keystone.py b/functest/utils/openstack/keystone.py
deleted file mode 100644
index f966468a3..000000000
--- a/functest/utils/openstack/keystone.py
+++ /dev/null
@@ -1,7 +0,0 @@
-#!/usr/bin/env python
-#
-# 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
-#
diff --git a/functest/utils/openstack/neutron.py b/functest/utils/openstack/neutron.py
deleted file mode 100644
index f966468a3..000000000
--- a/functest/utils/openstack/neutron.py
+++ /dev/null
@@ -1,7 +0,0 @@
-#!/usr/bin/env python
-#
-# 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
-#
diff --git a/functest/utils/openstack/nova.py b/functest/utils/openstack/nova.py
deleted file mode 100644
index f966468a3..000000000
--- a/functest/utils/openstack/nova.py
+++ /dev/null
@@ -1,7 +0,0 @@
-#!/usr/bin/env python
-#
-# 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
-#
diff --git a/functest/utils/openstack_clean.py b/functest/utils/openstack_clean.py
index ce61fcacf..29106d9ed 100755
--- a/functest/utils/openstack_clean.py
+++ b/functest/utils/openstack_clean.py
@@ -24,13 +24,13 @@
import time
+import logging
import yaml
-import functest.utils.functest_logger as ft_logger
import functest.utils.openstack_utils as os_utils
from functest.utils.constants import CONST
-logger = ft_logger.Logger("openstack_clean").getLogger()
+logger = logging.getLogger(__name__)
OS_SNAPSHOT_FILE = CONST.openstack_snapshot_file
@@ -428,4 +428,5 @@ def main():
if __name__ == '__main__':
+ logging.basicConfig()
main()
diff --git a/functest/utils/openstack_snapshot.py b/functest/utils/openstack_snapshot.py
index e64030f75..952fb7bbb 100755
--- a/functest/utils/openstack_snapshot.py
+++ b/functest/utils/openstack_snapshot.py
@@ -20,13 +20,13 @@
# http://www.apache.org/licenses/LICENSE-2.0
#
+import logging
import yaml
-import functest.utils.functest_logger as ft_logger
import functest.utils.openstack_utils as os_utils
from functest.utils.constants import CONST
-logger = ft_logger.Logger("openstack_snapshot").getLogger()
+logger = logging.getLogger(__name__)
OS_SNAPSHOT_FILE = CONST.openstack_snapshot_file
@@ -162,4 +162,5 @@ def main():
if __name__ == '__main__':
+ logging.basicConfig()
main()
diff --git a/functest/utils/openstack_tacker.py b/functest/utils/openstack_tacker.py
index 8327fdbe2..9fd9d5c47 100644
--- a/functest/utils/openstack_tacker.py
+++ b/functest/utils/openstack_tacker.py
@@ -11,13 +11,13 @@
# http://www.apache.org/licenses/LICENSE-2.0
##########################################################################
+import logging
from tackerclient.v1_0 import client as tackerclient
-import functest.utils.functest_logger as ft_logger
import functest.utils.openstack_utils as os_utils
import time
-logger = ft_logger.Logger("tacker_utils").getLogger()
+logger = logging.getLogger(__name__)
def get_tacker_client(other_creds={}):
diff --git a/functest/utils/openstack_utils.py b/functest/utils/openstack_utils.py
index 929a761e0..8bd950528 100644
--- a/functest/utils/openstack_utils.py
+++ b/functest/utils/openstack_utils.py
@@ -8,7 +8,7 @@
# http://www.apache.org/licenses/LICENSE-2.0
#
-import os
+import logging
import os.path
import re
import sys
@@ -23,10 +23,9 @@ from novaclient import client as novaclient
from keystoneclient import client as keystoneclient
from neutronclient.neutron import client as neutronclient
-import functest.utils.functest_logger as ft_logger
import functest.utils.functest_utils as ft_utils
-logger = ft_logger.Logger("openstack_utils").getLogger()
+logger = logging.getLogger(__name__)
DEFAULT_API_VERSION = '2'
DEFAULT_HEAT_API_VERSION = '1'
@@ -139,11 +138,11 @@ def get_credentials_for_rally():
endpoint_types = [('internalURL', 'internal'),
('publicURL', 'public'), ('adminURL', 'admin')]
- endpoint_type = os.getenv('OS_ENDPOINT_TYPE')
+ endpoint_type = get_endpoint_type_from_env()
if endpoint_type is not None:
cred_key = env_cred_dict.get('OS_ENDPOINT_TYPE')
for k, v in endpoint_types:
- if endpoint_type == k:
+ if endpoint_type == v:
rally_conf[cred_key] = v
region_name = os.getenv('OS_REGION_NAME')
@@ -158,6 +157,14 @@ def get_credentials_for_rally():
return rally_conf
+def get_endpoint_type_from_env():
+ endpoint_type = os.environ.get("OS_ENDPOINT_TYPE",
+ os.environ.get("OS_INTERFACE"))
+ if endpoint_type and "URL" in endpoint_type:
+ endpoint_type = endpoint_type.replace("URL", "")
+ return endpoint_type
+
+
def get_session_auth(other_creds={}):
loader = loading.get_plugin_loader('password')
creds = get_credentials(other_creds)
@@ -198,7 +205,9 @@ def get_keystone_client_version():
def get_keystone_client(other_creds={}):
sess = get_session(other_creds)
- return keystoneclient.Client(get_keystone_client_version(), session=sess)
+ return keystoneclient.Client(get_keystone_client_version(),
+ session=sess,
+ interface=os.getenv('OS_INTERFACE', 'admin'))
def get_nova_client_version():
@@ -277,7 +286,7 @@ def get_instances(nova_client):
try:
instances = nova_client.servers.list(search_opts={'all_tenants': 1})
return instances
- except Exception, e:
+ except Exception as e:
logger.error("Error [get_instances(nova_client)]: %s" % e)
return None
@@ -286,7 +295,7 @@ def get_instance_status(nova_client, instance):
try:
instance = nova_client.servers.get(instance.id)
return instance.status
- except Exception, e:
+ except Exception as e:
logger.error("Error [get_instance_status(nova_client)]: %s" % e)
return None
@@ -295,7 +304,7 @@ def get_instance_by_name(nova_client, instance_name):
try:
instance = nova_client.servers.find(name=instance_name)
return instance
- except Exception, e:
+ except Exception as e:
logger.error("Error [get_instance_by_name(nova_client, '%s')]: %s"
% (instance_name, e))
return None
@@ -325,7 +334,7 @@ def get_aggregates(nova_client):
try:
aggregates = nova_client.aggregates.list()
return aggregates
- except Exception, e:
+ except Exception as e:
logger.error("Error [get_aggregates(nova_client)]: %s" % e)
return None
@@ -335,7 +344,7 @@ def get_aggregate_id(nova_client, aggregate_name):
aggregates = get_aggregates(nova_client)
_id = [ag.id for ag in aggregates if ag.name == aggregate_name][0]
return _id
- except Exception, e:
+ except Exception as e:
logger.error("Error [get_aggregate_id(nova_client, %s)]:"
" %s" % (aggregate_name, e))
return None
@@ -345,7 +354,7 @@ def get_availability_zones(nova_client):
try:
availability_zones = nova_client.availability_zones.list()
return availability_zones
- except Exception, e:
+ except Exception as e:
logger.error("Error [get_availability_zones(nova_client)]: %s" % e)
return None
@@ -354,7 +363,7 @@ def get_availability_zone_names(nova_client):
try:
az_names = [az.zoneName for az in get_availability_zones(nova_client)]
return az_names
- except Exception, e:
+ except Exception as e:
logger.error("Error [get_availability_zone_names(nova_client)]:"
" %s" % e)
return None
@@ -372,7 +381,7 @@ def create_flavor(nova_client, flavor_name, ram, disk, vcpus, public=True):
# flavor extra specs are not configured, therefore skip the update
pass
- except Exception, e:
+ except Exception as e:
logger.error("Error [create_flavor(nova_client, '%s', '%s', '%s', "
"'%s')]: %s" % (flavor_name, ram, disk, vcpus, e))
return None
@@ -405,7 +414,7 @@ def get_floating_ips(nova_client):
try:
floating_ips = nova_client.floating_ips.list()
return floating_ips
- except Exception, e:
+ except Exception as e:
logger.error("Error [get_floating_ips(nova_client)]: %s" % e)
return None
@@ -418,7 +427,7 @@ def get_hypervisors(nova_client):
if hypervisor.state == "up":
nodes.append(hypervisor.hypervisor_hostname)
return nodes
- except Exception, e:
+ except Exception as e:
logger.error("Error [get_hypervisors(nova_client)]: %s" % e)
return None
@@ -427,7 +436,7 @@ def create_aggregate(nova_client, aggregate_name, av_zone):
try:
nova_client.aggregates.create(aggregate_name, av_zone)
return True
- except Exception, e:
+ except Exception as e:
logger.error("Error [create_aggregate(nova_client, %s, %s)]: %s"
% (aggregate_name, av_zone, e))
return None
@@ -438,7 +447,7 @@ def add_host_to_aggregate(nova_client, aggregate_name, compute_host):
aggregate_id = get_aggregate_id(nova_client, aggregate_name)
nova_client.aggregates.add_host(aggregate_id, compute_host)
return True
- except Exception, e:
+ except Exception as e:
logger.error("Error [add_host_to_aggregate(nova_client, %s, %s)]: %s"
% (aggregate_name, compute_host, e))
return None
@@ -450,7 +459,7 @@ def create_aggregate_with_host(
create_aggregate(nova_client, aggregate_name, av_zone)
add_host_to_aggregate(nova_client, aggregate_name, compute_host)
return True
- except Exception, e:
+ except Exception as e:
logger.error("Error [create_aggregate_with_host("
"nova_client, %s, %s, %s)]: %s"
% (aggregate_name, av_zone, compute_host, e))
@@ -543,7 +552,7 @@ def create_floating_ip(neutron_client):
ip_json = neutron_client.create_floatingip({'floatingip': props})
fip_addr = ip_json['floatingip']['floating_ip_address']
fip_id = ip_json['floatingip']['id']
- except Exception, e:
+ except Exception as e:
logger.error("Error [create_floating_ip(neutron_client)]: %s" % e)
return None
return {'fip_addr': fip_addr, 'fip_id': fip_id}
@@ -553,7 +562,7 @@ def add_floating_ip(nova_client, server_id, floatingip_addr):
try:
nova_client.servers.add_floating_ip(server_id, floatingip_addr)
return True
- except Exception, e:
+ except Exception as e:
logger.error("Error [add_floating_ip(nova_client, '%s', '%s')]: %s"
% (server_id, floatingip_addr, e))
return False
@@ -563,7 +572,7 @@ def delete_instance(nova_client, instance_id):
try:
nova_client.servers.force_delete(instance_id)
return True
- except Exception, e:
+ except Exception as e:
logger.error("Error [delete_instance(nova_client, '%s')]: %s"
% (instance_id, e))
return False
@@ -573,7 +582,7 @@ def delete_floating_ip(nova_client, floatingip_id):
try:
nova_client.floating_ips.delete(floatingip_id)
return True
- except Exception, e:
+ except Exception as e:
logger.error("Error [delete_floating_ip(nova_client, '%s')]: %s"
% (floatingip_id, e))
return False
@@ -584,7 +593,7 @@ def remove_host_from_aggregate(nova_client, aggregate_name, compute_host):
aggregate_id = get_aggregate_id(nova_client, aggregate_name)
nova_client.aggregates.remove_host(aggregate_id, compute_host)
return True
- except Exception, e:
+ except Exception as e:
logger.error("Error [remove_host_from_aggregate(nova_client, %s, %s)]:"
" %s" % (aggregate_name, compute_host, e))
return False
@@ -603,7 +612,7 @@ def delete_aggregate(nova_client, aggregate_name):
remove_hosts_from_aggregate(nova_client, aggregate_name)
nova_client.aggregates.delete(aggregate_name)
return True
- except Exception, e:
+ except Exception as e:
logger.error("Error [delete_aggregate(nova_client, %s)]: %s"
% (aggregate_name, e))
return False
@@ -706,7 +715,7 @@ def create_neutron_net(neutron_client, name):
network = neutron_client.create_network(body=json_body)
network_dict = network['network']
return network_dict['id']
- except Exception, e:
+ except Exception as e:
logger.error("Error [create_neutron_net(neutron_client, '%s')]: %s"
% (name, e))
return None
@@ -718,7 +727,7 @@ def create_neutron_subnet(neutron_client, name, cidr, net_id):
try:
subnet = neutron_client.create_subnet(body=json_body)
return subnet['subnets'][0]['id']
- except Exception, e:
+ except Exception as e:
logger.error("Error [create_neutron_subnet(neutron_client, '%s', "
"'%s', '%s')]: %s" % (name, cidr, net_id, e))
return None
@@ -729,7 +738,7 @@ def create_neutron_router(neutron_client, name):
try:
router = neutron_client.create_router(json_body)
return router['router']['id']
- except Exception, e:
+ except Exception as e:
logger.error("Error [create_neutron_router(neutron_client, '%s')]: %s"
% (name, e))
return None
@@ -745,7 +754,7 @@ def create_neutron_port(neutron_client, name, network_id, ip):
try:
port = neutron_client.create_port(body=json_body)
return port['port']['id']
- except Exception, e:
+ except Exception as e:
logger.error("Error [create_neutron_port(neutron_client, '%s', '%s', "
"'%s')]: %s" % (name, network_id, ip, e))
return None
@@ -756,7 +765,7 @@ def update_neutron_net(neutron_client, network_id, shared=False):
try:
neutron_client.update_network(network_id, body=json_body)
return True
- except Exception, e:
+ except Exception as e:
logger.error("Error [update_neutron_net(neutron_client, '%s', '%s')]: "
"%s" % (network_id, str(shared), e))
return False
@@ -770,7 +779,7 @@ def update_neutron_port(neutron_client, port_id, device_owner):
port = neutron_client.update_port(port=port_id,
body=json_body)
return port['port']['id']
- except Exception, e:
+ except Exception as e:
logger.error("Error [update_neutron_port(neutron_client, '%s', '%s')]:"
" %s" % (port_id, device_owner, e))
return None
@@ -781,7 +790,7 @@ def add_interface_router(neutron_client, router_id, subnet_id):
try:
neutron_client.add_interface_router(router=router_id, body=json_body)
return True
- except Exception, e:
+ except Exception as e:
logger.error("Error [add_interface_router(neutron_client, '%s', "
"'%s')]: %s" % (router_id, subnet_id, e))
return False
@@ -793,7 +802,7 @@ def add_gateway_router(neutron_client, router_id):
try:
neutron_client.add_gateway_router(router_id, router_dict)
return True
- except Exception, e:
+ except Exception as e:
logger.error("Error [add_gateway_router(neutron_client, '%s')]: %s"
% (router_id, e))
return False
@@ -803,7 +812,7 @@ def delete_neutron_net(neutron_client, network_id):
try:
neutron_client.delete_network(network_id)
return True
- except Exception, e:
+ except Exception as e:
logger.error("Error [delete_neutron_net(neutron_client, '%s')]: %s"
% (network_id, e))
return False
@@ -813,7 +822,7 @@ def delete_neutron_subnet(neutron_client, subnet_id):
try:
neutron_client.delete_subnet(subnet_id)
return True
- except Exception, e:
+ except Exception as e:
logger.error("Error [delete_neutron_subnet(neutron_client, '%s')]: %s"
% (subnet_id, e))
return False
@@ -823,7 +832,7 @@ def delete_neutron_router(neutron_client, router_id):
try:
neutron_client.delete_router(router=router_id)
return True
- except Exception, e:
+ except Exception as e:
logger.error("Error [delete_neutron_router(neutron_client, '%s')]: %s"
% (router_id, e))
return False
@@ -833,7 +842,7 @@ def delete_neutron_port(neutron_client, port_id):
try:
neutron_client.delete_port(port_id)
return True
- except Exception, e:
+ except Exception as e:
logger.error("Error [delete_neutron_port(neutron_client, '%s')]: %s"
% (port_id, e))
return False
@@ -845,7 +854,7 @@ def remove_interface_router(neutron_client, router_id, subnet_id):
neutron_client.remove_interface_router(router=router_id,
body=json_body)
return True
- except Exception, e:
+ except Exception as e:
logger.error("Error [remove_interface_router(neutron_client, '%s', "
"'%s')]: %s" % (router_id, subnet_id, e))
return False
@@ -855,7 +864,7 @@ def remove_gateway_router(neutron_client, router_id):
try:
neutron_client.remove_gateway_router(router_id)
return True
- except Exception, e:
+ except Exception as e:
logger.error("Error [remove_gateway_router(neutron_client, '%s')]: %s"
% (router_id, e))
return False
@@ -985,7 +994,7 @@ def get_security_groups(neutron_client):
security_groups = neutron_client.list_security_groups()[
'security_groups']
return security_groups
- except Exception, e:
+ except Exception as e:
logger.error("Error [get_security_groups(neutron_client)]: %s" % e)
return None
@@ -1006,7 +1015,7 @@ def create_security_group(neutron_client, sg_name, sg_description):
try:
secgroup = neutron_client.create_security_group(json_body)
return secgroup['security_group']
- except Exception, e:
+ except Exception as e:
logger.error("Error [create_security_group(neutron_client, '%s', "
"'%s')]: %s" % (sg_name, sg_description, e))
return None
@@ -1061,7 +1070,7 @@ def get_security_group_rules(neutron_client, sg_id):
security_rules = [rule for rule in security_rules
if rule["security_group_id"] == sg_id]
return security_rules
- except Exception, e:
+ except Exception as e:
logger.error("Error [get_security_group_rules(neutron_client, sg_id)]:"
" %s" % e)
return None
@@ -1080,7 +1089,7 @@ def check_security_group_rules(neutron_client, sg_id, direction, protocol,
return True
else:
return False
- except Exception, e:
+ except Exception as e:
logger.error("Error [check_security_group_rules("
" neutron_client, sg_id, direction,"
" protocol, port_min=None, port_max=None)]: "
@@ -1132,7 +1141,7 @@ def add_secgroup_to_instance(nova_client, instance_id, secgroup_id):
try:
nova_client.servers.add_security_group(instance_id, secgroup_id)
return True
- except Exception, e:
+ except Exception as e:
logger.error("Error [add_secgroup_to_instance(nova_client, '%s', "
"'%s')]: %s" % (instance_id, secgroup_id, e))
return False
@@ -1148,7 +1157,7 @@ def update_sg_quota(neutron_client, tenant_id, sg_quota, sg_rule_quota):
neutron_client.update_quota(tenant_id=tenant_id,
body=json_body)
return True
- except Exception, e:
+ except Exception as e:
logger.error("Error [update_sg_quota(neutron_client, '%s', '%s', "
"'%s')]: %s" % (tenant_id, sg_quota, sg_rule_quota, e))
return False
@@ -1158,7 +1167,7 @@ def delete_security_group(neutron_client, secgroup_id):
try:
neutron_client.delete_security_group(secgroup_id)
return True
- except Exception, e:
+ except Exception as e:
logger.error("Error [delete_security_group(neutron_client, '%s')]: %s"
% (secgroup_id, e))
return False
@@ -1171,7 +1180,7 @@ def get_images(nova_client):
try:
images = nova_client.images.list()
return images
- except Exception, e:
+ except Exception as e:
logger.error("Error [get_images]: %s" % e)
return None
@@ -1207,7 +1216,7 @@ def create_glance_image(glance_client, image_name, file_path, disk="qcow2",
with open(file_path) as image_data:
glance_client.images.upload(image_id, image_data)
return image_id
- except Exception, e:
+ except Exception as e:
logger.error("Error [create_glance_image(glance_client, '%s', '%s', "
"'%s')]: %s" % (image_name, file_path, public, e))
return None
@@ -1237,7 +1246,7 @@ def delete_glance_image(nova_client, image_id):
try:
nova_client.images.delete(image_id)
return True
- except Exception, e:
+ except Exception as e:
logger.error("Error [delete_glance_image(nova_client, '%s')]: %s"
% (image_id, e))
return False
@@ -1250,7 +1259,7 @@ def get_volumes(cinder_client):
try:
volumes = cinder_client.volumes.list(search_opts={'all_tenants': 1})
return volumes
- except Exception, e:
+ except Exception as e:
logger.error("Error [get_volumes(cinder_client)]: %s" % e)
return None
@@ -1263,7 +1272,7 @@ def list_volume_types(cinder_client, public=True, private=True):
if not private:
volume_types = [vt for vt in volume_types if vt.is_public]
return volume_types
- except Exception, e:
+ except Exception as e:
logger.error("Error [list_volume_types(cinder_client)]: %s" % e)
return None
@@ -1272,7 +1281,7 @@ def create_volume_type(cinder_client, name):
try:
volume_type = cinder_client.volume_types.create(name)
return volume_type
- except Exception, e:
+ except Exception as e:
logger.error("Error [create_volume_type(cinder_client, '%s')]: %s"
% (name, e))
return None
@@ -1287,7 +1296,7 @@ def update_cinder_quota(cinder_client, tenant_id, vols_quota,
try:
cinder_client.quotas.update(tenant_id, **quotas_values)
return True
- except Exception, e:
+ except Exception as e:
logger.error("Error [update_cinder_quota(cinder_client, '%s', '%s', "
"'%s' '%s')]: %s" % (tenant_id, vols_quota,
snapshots_quota, gigabytes_quota, e))
@@ -1305,7 +1314,7 @@ def delete_volume(cinder_client, volume_id, forced=False):
else:
cinder_client.volumes.delete(volume_id)
return True
- except Exception, e:
+ except Exception as e:
logger.error("Error [delete_volume(cinder_client, '%s', '%s')]: %s"
% (volume_id, str(forced), e))
return False
@@ -1315,7 +1324,7 @@ def delete_volume_type(cinder_client, volume_type):
try:
cinder_client.volume_types.delete(volume_type)
return True
- except Exception, e:
+ except Exception as e:
logger.error("Error [delete_volume_type(cinder_client, '%s')]: %s"
% (volume_type, e))
return False
@@ -1331,7 +1340,7 @@ def get_tenants(keystone_client):
else:
tenants = keystone_client.tenants.list()
return tenants
- except Exception, e:
+ except Exception as e:
logger.error("Error [get_tenants(keystone_client)]: %s" % e)
return None
@@ -1340,7 +1349,7 @@ def get_users(keystone_client):
try:
users = keystone_client.users.list()
return users
- except Exception, e:
+ except Exception as e:
logger.error("Error [get_users(keystone_client)]: %s" % e)
return None
@@ -1388,7 +1397,7 @@ def create_tenant(keystone_client, tenant_name, tenant_description):
tenant_description,
enabled=True)
return tenant.id
- except Exception, e:
+ except Exception as e:
logger.error("Error [create_tenant(keystone_client, '%s', '%s')]: %s"
% (tenant_name, tenant_description, e))
return None
@@ -1419,7 +1428,7 @@ def create_user(keystone_client, user_name, user_password,
tenant_id,
enabled=True)
return user.id
- except Exception, e:
+ except Exception as e:
logger.error("Error [create_user(keystone_client, '%s', '%s', '%s'"
"'%s')]: %s" % (user_name, user_password,
user_email, tenant_id, e))
@@ -1444,7 +1453,7 @@ def add_role_user(keystone_client, user_id, role_id, tenant_id):
else:
keystone_client.roles.add_user_role(user_id, role_id, tenant_id)
return True
- except Exception, e:
+ except Exception as e:
logger.error("Error [add_role_user(keystone_client, '%s', '%s'"
"'%s')]: %s " % (user_id, role_id, tenant_id, e))
return False
@@ -1457,7 +1466,7 @@ def delete_tenant(keystone_client, tenant_id):
else:
keystone_client.tenants.delete(tenant_id)
return True
- except Exception, e:
+ except Exception as e:
logger.error("Error [delete_tenant(keystone_client, '%s')]: %s"
% (tenant_id, e))
return False
@@ -1467,7 +1476,7 @@ def delete_user(keystone_client, user_id):
try:
keystone_client.users.delete(user_id)
return True
- except Exception, e:
+ except Exception as e:
logger.error("Error [delete_user(keystone_client, '%s')]: %s"
% (user_id, e))
return False
@@ -1480,6 +1489,6 @@ def get_resource(heat_client, stack_id, resource):
try:
resources = heat_client.resources.get(stack_id, resource)
return resources
- except Exception, e:
+ except Exception as e:
logger.error("Error [get_resource]: %s" % e)
return None
diff --git a/requirements.txt b/requirements.txt
index 92f16bcca..65b369799 100644
--- a/requirements.txt
+++ b/requirements.txt
@@ -14,17 +14,19 @@ python-keystoneclient==3.5.0
python-neutronclient==6.0.0
python-novaclient==6.0.0
python-congressclient==1.5.0
-virtualenv==15.1.0
+python-tackerclient==0.7.0
pexpect==4.0
requests>=2.8.0
-robotframework==2.9.1
-robotframework-requests==0.3.8
-robotframework-sshlibrary==2.1.1
+robotframework==3.0.2
+robotframework-httplibrary==0.4.2
+robotframework-requests==0.4.7
+robotframework-sshlibrary==2.1.3
+jmespath==0.9.2
configObj==5.0.6
Flask==0.10.1
xmltodict==0.9.2
scp==0.10.2
-paramiko==1.16.0
+paramiko==2.1.2
subprocess32
shyaml
dnspython
@@ -32,3 +34,6 @@ Pillow==3.3.0
click==6.6
openbaton-cli==2.2.1-beta7
mock==1.3.0
+iniparse==0.4
+PrettyTable>=0.7.1,<0.8 # BSD
+six>=1.9.0 # MIT
diff --git a/run_unit_tests.sh b/run_unit_tests.sh
index 9780de7ac..86096fabf 100755
--- a/run_unit_tests.sh
+++ b/run_unit_tests.sh
@@ -14,13 +14,16 @@ fi
# ***************
echo "Running unit tests..."
+sudo apt-get install -y build-essential python-dev python-pip
+sudo pip install virtualenv==15.1.0
+
# start vitual env
virtualenv $WORKSPACE/functest_venv
source $WORKSPACE/functest_venv/bin/activate
# install python packages
-sudo apt-get install -y build-essential python-dev python-pip
pip install --upgrade pip
+pip install -r $WORKSPACE/requirements.txt
pip install -r $WORKSPACE/test-requirements.txt
pip install $WORKSPACE
diff --git a/test-requirements.txt b/test-requirements.txt
index 471e9c30a..b0d4ff8d1 100644
--- a/test-requirements.txt
+++ b/test-requirements.txt
@@ -5,24 +5,6 @@
# which accompanies this distribution, and is available at
# http://www.apache.org/licenses/LICENSE-2.0
#
-click==6.6
coverage==4.1
-dnspython==1.15.0
-gitpython==1.0.1
-iniparse==0.4
mock==1.3.0
nose==1.3.7
-python-ceilometerclient==2.6.2
-python-congressclient==1.5.0
-python-heatclient==1.7.0
-python-keystoneclient==3.5.0
-python-neutronclient==6.0.0
-python-openstackclient==2.3.0
-python-tackerclient==0.7.0
-pyyaml==3.10
-requests==2.8.0
-robotframework==2.9.1
-robotframework-requests==0.3.8
-robotframework-sshlibrary==2.1.1
-subprocess32==3.2.7
-virtualenv==15.1.0