diff options
46 files changed, 738 insertions, 159 deletions
diff --git a/.gitmodules b/.gitmodules new file mode 100644 index 000000000..78668cf6a --- /dev/null +++ b/.gitmodules @@ -0,0 +1,3 @@ +[submodule "docs/com/pres/reveal.js"] + path = docs/com/pres/reveal.js + url = https://github.com/hakimel/reveal.js.git diff --git a/docker/Dockerfile b/docker/Dockerfile index 134b8ef3c..4c0995b97 100644 --- a/docker/Dockerfile +++ b/docker/Dockerfile @@ -120,8 +120,20 @@ RUN cd ${REPOS_DIR}/barometer \ && pip install . RUN find ${FUNCTEST_REPO_DIR} -name "*.py" \ - -not -path "*tests/unit*" |xargs grep __main__ |cut -d\: -f 1 |xargs chmod -c 755 \ - && find ${FUNCTEST_REPO_DIR} -name "*.sh" |xargs grep \#\! |cut -d\: -f 1 |xargs chmod -c 755 + -not -path "*tests/unit*" \ + -not -path "*functest_venv*" \ + |xargs grep -L __main__ |cut -d\: -f 1 |xargs chmod -c 644 \ + && find ${FUNCTEST_REPO_DIR} -name "*.sh" \ + -not -path "*functest_venv*" \ + |xargs grep -L \#\! |cut -d\: -f 1 |xargs chmod -c 644 + +RUN find ${FUNCTEST_REPO_DIR} -name "*.py" \ + -not -path "*tests/unit*" \ + -not -path "*functest_venv*" \ + |xargs grep __main__ |cut -d\: -f 1 |xargs chmod -c 755 \ + && find ${FUNCTEST_REPO_DIR} -name "*.sh" \ + -not -path "*functest_venv*" \ + |xargs grep \#\! |cut -d\: -f 1 |xargs chmod -c 755 RUN /bin/bash ${REPOS_DIR}/parser/tests/parser_install.sh ${REPOS_DIR} RUN ${REPOS_DIR}/rally/install_rally.sh --yes diff --git a/docker/Dockerfile.aarch64 b/docker/Dockerfile.aarch64 index da1ce2df7..60f72a297 100644 --- a/docker/Dockerfile.aarch64 +++ b/docker/Dockerfile.aarch64 @@ -15,6 +15,7 @@ LABEL version="0.1" description="OPNFV Functest Aarch64 Docker container" ARG BRANCH=master ARG RALLY_TAG=0.8.1 ARG TEMPEST_TAG=15.0.0 +ARG REFSTACK_TAG=15.0.0 ARG ODL_TAG=release/beryllium-sr4 ARG OPENSTACK_TAG=stable/mitaka ARG KINGBIRD_TAG=0.2.2 @@ -93,6 +94,7 @@ RUN git clone --depth 1 -b $OPENSTACK_TAG https://github.com/openstack/networkin RUN git clone --depth 1 -b $KINGBIRD_TAG https://github.com/openstack/kingbird.git ${REPOS_DIR}/kingbird RUN git clone --depth 1 -b $RALLY_TAG https://github.com/openstack/rally.git ${REPOS_DIR}/rally RUN git clone --depth 1 -b $TEMPEST_TAG https://github.com/openstack/tempest.git ${REPOS_DIR}/tempest +RUN git clone https://github.com/openstack/refstack-client ${REPOS_DIR}/refstack-client # other repositories RUN git clone --depth 1 -b $ODL_TAG https://git.opendaylight.org/gerrit/p/integration/test.git ${REPOS_DIR}/odl_test @@ -110,8 +112,20 @@ RUN cd ${RELENG_MODULE_DIR} \ && pip install -e . RUN find ${FUNCTEST_REPO_DIR} -name "*.py" \ - -not -path "*tests/unit*" |xargs grep __main__ |cut -d\: -f 1 |xargs chmod -c 755 \ - && find ${FUNCTEST_REPO_DIR} -name "*.sh" |xargs grep \#\! |cut -d\: -f 1 |xargs chmod -c 755 + -not -path "*tests/unit*" \ + -not -path "*functest_venv*" \ + |xargs grep -L __main__ |cut -d\: -f 1 |xargs chmod -c 644 && + find ${FUNCTEST_REPO_DIR} -name "*.sh" \ + -not -path "*functest_venv*" \ + |xargs grep -L \#\! |cut -d\: -f 1 |xargs chmod -c 644 + +RUN find ${FUNCTEST_REPO_DIR} -name "*.py" \ + -not -path "*tests/unit*" \ + -not -path "*functest_venv*" \ + |xargs grep __main__ |cut -d\: -f 1 |xargs chmod -c 755 && + find ${FUNCTEST_REPO_DIR} -name "*.sh" \ + -not -path "*functest_venv*" \ + |xargs grep \#\! |cut -d\: -f 1 |xargs chmod -c 755 RUN /bin/bash ${REPOS_DIR}/parser/tests/parser_install.sh ${REPOS_DIR} RUN ${REPOS_DIR}/rally/install_rally.sh --yes @@ -135,6 +149,9 @@ RUN cd ${REPOS_DIR}/bgpvpn && pip install -e . # Kingbird integration RUN cd ${REPOS_DIR}/kingbird && pip install -e . +# refstack-client integration +RUN cd ${REPOS_DIR}/refstack-client && ./setup_env -t ${REFSTACK_TAG} + RUN /bin/bash -c ". /etc/profile.d/rvm.sh \ && cd ${REPOS_VNFS_DIR}/vims-test \ && rvm autolibs enable" diff --git a/docs/com/README.txt b/docs/com/README.txt deleted file mode 100644 index 62d616b49..000000000 --- a/docs/com/README.txt +++ /dev/null @@ -1,9 +0,0 @@ -This com folder contains the images, html and css files used to create -communication based on reveal.js -All the files are licensed under Creative Commons Attribution 4.0 -International License. -.. http://creativecommons.org/licenses/by/4.0 - -You can download reveal.js at: https://github.com/hakimel/reveal.js/ -Then you must put images and css on existing directory and add the pres -directory diff --git a/docs/com/pres/Summit/Berlin-2016/conversation.html b/docs/com/pres/Summit/Berlin-2016/conversation.html index b56b1e100..356c2ad1e 100755 --- a/docs/com/pres/Summit/Berlin-2016/conversation.html +++ b/docs/com/pres/Summit/Berlin-2016/conversation.html @@ -14,18 +14,18 @@ <meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=no, minimal-ui"> - <link rel="stylesheet" href="../../../css/reveal.css"> + <link rel="stylesheet" href="../../reveal.js/css/reveal.css"> <link rel="stylesheet" href="../../../css/theme/OPNFV-Berlin.css" id="theme"> <!-- Code syntax highlighting --> - <link rel="stylesheet" href="../../../lib/css/zenburn.css"> + <link rel="stylesheet" href="../../reveal.js/lib/css/zenburn.css"> <!-- Printing and PDF exports --> <script> var link = document.createElement( 'link' ); link.rel = 'stylesheet'; link.type = 'text/css'; - link.href = window.location.search.match( /print-pdf/gi ) ? '../../../css/print/pdf.css' : '../../../css/print/paper.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> @@ -219,8 +219,8 @@ </div> </div> - <script src="../../../lib/js/head.min.js"></script> - <script src="../../../js/reveal.js"></script> + <script src="../../reveal.js/lib/js/head.min.js"></script> + <script src="../../reveal.js/js/reveal.js"></script> <script> @@ -236,12 +236,12 @@ // Optional reveal.js plugins dependencies: [ - { src: '../../../lib/js/classList.js', condition: function() { return !document.body.classList; } }, - { src: '../../../plugin/markdown/marked.js', condition: function() { return !!document.querySelector( '[data-markdown]' ); } }, - { src: '../../../plugin/markdown/markdown.js', condition: function() { return !!document.querySelector( '[data-markdown]' ); } }, - { src: '../../../plugin/highlight/highlight.js', async: true, condition: function() { return !!document.querySelector( 'pre code' ); }, callback: function() { hljs.initHighlightingOnLoad(); } }, - { src: '../../../plugin/zoom-js/zoom.js', async: true }, - { src: '../../../plugin/notes/notes.js', async: true } + { src: '../../reveal.js/lib/js/classList.js', condition: function() { return !document.body.classList; } }, + { 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, condition: function() { return !!document.querySelector( 'pre code' ); }, callback: function() { hljs.initHighlightingOnLoad(); } }, + { src: '../../reveal.js/plugin/zoom-js/zoom.js', async: true }, + { src: '../../reveal.js/plugin/notes/notes.js', async: true } ] }); diff --git a/docs/com/pres/Summit/Berlin-2016/summit-Berlin.html b/docs/com/pres/Summit/Berlin-2016/summit-Berlin.html index 8369443f7..97fa66c18 100755 --- a/docs/com/pres/Summit/Berlin-2016/summit-Berlin.html +++ b/docs/com/pres/Summit/Berlin-2016/summit-Berlin.html @@ -14,23 +14,23 @@ <meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=no, minimal-ui"> - <link rel="stylesheet" href="../../../css/reveal.css"> + <link rel="stylesheet" href="../../reveal.js/css/reveal.css"> <link rel="stylesheet" href="../../../css/theme/OPNFV-Berlin.css" id="theme"> <!-- Code syntax highlighting --> - <link rel="stylesheet" href="../../../lib/css/zenburn.css"> + <link rel="stylesheet" href="../../reveal.js/lib/css/zenburn.css"> <!-- Printing and PDF exports --> <script> var link = document.createElement( 'link' ); link.rel = 'stylesheet'; link.type = 'text/css'; - link.href = window.location.search.match( /print-pdf/gi ) ? '../../../css/print/pdf.css' : '../../../css/print/paper.css'; + link.href = window.location.search.match( /print-pdf/gi ) ? '../../reveal.js/css/print/pdf.css' : '../../../css/print/paper.css'; document.getElementsByTagName( 'head' )[0].appendChild( link ); </script> <!--[if lt IE 9]> - <script src="lib/js/html5shiv.js"></script> + <script src="l../../reveal.jsml5shiv.js"></script> <![endif]--> </head> @@ -277,12 +277,12 @@ </div> <div class='footer'> - <img src="../../../img/logo-OPNFV-Berlin.png" alt="OPNFV logo"> + <img src="../../../img/logo-OPNFV-Berlin.png" alt="OPNFV logo"> </div> </div> - <script src="../../../lib/js/head.min.js"></script> - <script src="../../../js/reveal.js"></script> + <script src="../../reveal.js/lib/js/head.min.js"></script> + <script src="../../reveal.js/js/reveal.js"></script> <script> @@ -298,12 +298,12 @@ // Optional reveal.js plugins dependencies: [ - { src: '../../../lib/js/classList.js', condition: function() { return !document.body.classList; } }, - { src: '../../../plugin/markdown/marked.js', condition: function() { return !!document.querySelector( '[data-markdown]' ); } }, - { src: '../../../plugin/markdown/markdown.js', condition: function() { return !!document.querySelector( '[data-markdown]' ); } }, - { src: '../../../plugin/highlight/highlight.js', async: true, condition: function() { return !!document.querySelector( 'pre code' ); }, callback: function() { hljs.initHighlightingOnLoad(); } }, - { src: '../../../plugin/zoom-js/zoom.js', async: true }, - { src: '../../../plugin/notes/notes.js', async: true } + { src: '../../reveal.js/lib/js/classList.js', condition: function() { return !document.body.classList; } }, + { 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, condition: function() { return !!document.querySelector( 'pre code' ); }, callback: function() { hljs.initHighlightingOnLoad(); } }, + { src: '../../reveal.js/plugin/zoom-js/zoom.js', async: true }, + { src: '../../reveal.js/plugin/notes/notes.js', async: true } ] }); diff --git a/docs/com/pres/Summit/Berlin-2016/testapi.html b/docs/com/pres/Summit/Berlin-2016/testapi.html index 16f97c44d..c40637cbf 100755 --- a/docs/com/pres/Summit/Berlin-2016/testapi.html +++ b/docs/com/pres/Summit/Berlin-2016/testapi.html @@ -14,18 +14,18 @@ <meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=no, minimal-ui"> - <link rel="stylesheet" href="../../../css/reveal.css"> + <link rel="stylesheet" href="../../reveal.js/css/reveal.css"> <link rel="stylesheet" href="../../../css/theme/OPNFV-Berlin.css" id="theme"> <!-- Code syntax highlighting --> - <link rel="stylesheet" href="../../../lib/css/zenburn.css"> + <link rel="stylesheet" href="../../reveal.js/lib/css/zenburn.css"> <!-- Printing and PDF exports --> <script> var link = document.createElement( 'link' ); link.rel = 'stylesheet'; link.type = 'text/css'; - link.href = window.location.search.match( /print-pdf/gi ) ? '../../../css/print/pdf.css' : '../../../css/print/paper.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> @@ -242,8 +242,8 @@ OK </div> </div> - <script src="../../../lib/js/head.min.js"></script> - <script src="../../../js/reveal.js"></script> + <script src="../../reveal.js/lib/js/head.min.js"></script> + <script src="../../reveal.js/js/reveal.js"></script> <script> @@ -259,12 +259,12 @@ OK // Optional reveal.js plugins dependencies: [ - { src: '../../../lib/js/classList.js', condition: function() { return !document.body.classList; } }, - { src: '../../../plugin/markdown/marked.js', condition: function() { return !!document.querySelector( '[data-markdown]' ); } }, - { src: '../../../plugin/markdown/markdown.js', condition: function() { return !!document.querySelector( '[data-markdown]' ); } }, - { src: '../../../plugin/highlight/highlight.js', async: true, condition: function() { return !!document.querySelector( 'pre code' ); }, callback: function() { hljs.initHighlightingOnLoad(); } }, - { src: '../../../plugin/zoom-js/zoom.js', async: true }, - { src: '../../../plugin/notes/notes.js', async: true } + { src: '../../reveal.js/lib/js/classList.js', condition: function() { return !document.body.classList; } }, + { 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, condition: function() { return !!document.querySelector( 'pre code' ); }, callback: function() { hljs.initHighlightingOnLoad(); } }, + { src: '../../reveal.js/plugin/zoom-js/zoom.js', async: true }, + { src: '../../reveal.js/plugin/notes/notes.js', async: true } ] }); diff --git a/docs/com/pres/dashboard/dashboard_status.html b/docs/com/pres/dashboard/dashboard_status.html index 7d46a74c5..1321afa0c 100755 --- a/docs/com/pres/dashboard/dashboard_status.html +++ b/docs/com/pres/dashboard/dashboard_status.html @@ -14,18 +14,18 @@ <meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=no, minimal-ui"> - <link rel="stylesheet" href="../../css/reveal.css"> + <link rel="stylesheet" href="../reveal.js/css/reveal.css"> <link rel="stylesheet" href="../../css/theme/OPNFV.css" id="theme"> <!-- Code syntax highlighting --> - <link rel="stylesheet" href="../../lib/css/zenburn.css"> + <link rel="stylesheet" href="../reveal.js/lib/css/zenburn.css"> <!-- Printing and PDF exports --> <script> var link = document.createElement( 'link' ); link.rel = 'stylesheet'; link.type = 'text/css'; - link.href = window.location.search.match( /print-pdf/gi ) ? '../../css/print/pdf.css' : '../../css/print/paper.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> @@ -114,8 +114,8 @@ </div> </div> - <script src="../../lib/js/head.min.js"></script> - <script src="../../js/reveal.js"></script> + <script src="../reveal.js/lib/js/head.min.js"></script> + <script src="../reveal.js/js/reveal.js"></script> <script> @@ -131,12 +131,12 @@ // Optional reveal.js plugins dependencies: [ - { src: '../../lib/js/classList.js', condition: function() { return !document.body.classList; } }, - { src: '../../plugin/markdown/marked.js', condition: function() { return !!document.querySelector( '[data-markdown]' ); } }, - { src: '../../plugin/markdown/markdown.js', condition: function() { return !!document.querySelector( '[data-markdown]' ); } }, - { src: '../../plugin/highlight/highlight.js', async: true, condition: function() { return !!document.querySelector( 'pre code' ); }, callback: function() { hljs.initHighlightingOnLoad(); } }, - { src: '../../plugin/zoom-js/zoom.js', async: true }, - { src: '../../plugin/notes/notes.js', async: true } + { src: '../reveal.js/lib/js/classList.js', condition: function() { return !document.body.classList; } }, + { 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, condition: function() { return !!document.querySelector( 'pre code' ); }, callback: function() { hljs.initHighlightingOnLoad(); } }, + { src: '../reveal.js/plugin/zoom-js/zoom.js', async: true }, + { src: '../reveal.js/plugin/notes/notes.js', async: true } ] }); diff --git a/docs/com/pres/reveal.js b/docs/com/pres/reveal.js new file mode 160000 +Subproject a349ff43c58c23f9c837b8ea9b5fc7d4761b8de diff --git a/functest/ci/__init__.py b/functest/ci/__init__.py index e69de29bb..e69de29bb 100755..100644 --- a/functest/ci/__init__.py +++ b/functest/ci/__init__.py diff --git a/functest/ci/check_os.sh b/functest/ci/check_os.sh index 2c5c021c7..3920b7ac6 100755 --- a/functest/ci/check_os.sh +++ b/functest/ci/check_os.sh @@ -26,6 +26,11 @@ verify_connectivity() { return 1 } +verify_SSL_connectivity() { + openssl s_client -connect $1:$2 &>/dev/null + return $? +} + check_service() { local service cmd service=$1 @@ -63,10 +68,16 @@ fi echo "Checking OpenStack endpoints:" publicURL=$(openstack catalog show identity |awk '/public/ {print $4}') -publicIP=$(echo $publicURL|sed 's/^.*http\:\/\///'|sed 's/.[^:]*$//') +publicIP=$(echo $publicURL|sed 's/^.*http.*\:\/\///'|sed 's/.[^:]*$//') publicPort=$(echo $publicURL|sed 's/^.*://'|sed 's/\/.*$//') -echo ">>Verifying connectivity to the public endpoint $publicIP:$publicPort..." -verify_connectivity $publicIP $publicPort +https_enabled=$(echo $publicURL | grep 'https') +if [[ -n $https_enabled ]]; then + echo ">>Verifying SSL connectivity to the public endpoint $publicIP:$publicPort..." + verify_SSL_connectivity $publicIP $publicPort +else + echo ">>Verifying connectivity to the public endpoint $publicIP:$publicPort..." + verify_connectivity $publicIP $publicPort +fi RETVAL=$? if [ $RETVAL -ne 0 ]; then echo "ERROR: Cannot talk to the public endpoint $publicIP:$publicPort ." @@ -81,10 +92,16 @@ if [ -z ${adminURL} ]; then openstack catalog show identity exit 1 fi -adminIP=$(echo $adminURL|sed 's/^.*http\:\/\///'|sed 's/.[^:]*$//') +adminIP=$(echo $adminURL|sed 's/^.*http.*\:\/\///'|sed 's/.[^:]*$//') adminPort=$(echo $adminURL|sed 's/^.*://'|sed 's/.[^\/]*$//') -echo ">>Verifying connectivity to the admin endpoint $adminIP:$adminPort..." -verify_connectivity $adminIP $adminPort +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 ." diff --git a/functest/ci/config_functest.yaml b/functest/ci/config_functest.yaml index 00e44ad59..78f6257c8 100755 --- a/functest/ci/config_functest.yaml +++ b/functest/ci/config_functest.yaml @@ -125,7 +125,7 @@ rally: refstack: tempest_conf_path: openstack/refstack_client/tempest.conf - defcore_list: openstack/refstack_client/defcore_201608.txt + defcore_list: openstack/refstack_client/defcore.txt vnf: aaa: @@ -200,4 +200,6 @@ example: sg_desc: Example Security group results: + # you can also set a dir (e.g. /home/opnfv/db) to dump results + # test_db_url: file:///home/opnfv/db test_db_url: http://testresults.opnfv.org/test/api/v1 diff --git a/functest/ci/generate_report.py b/functest/ci/generate_report.py index 89d8fc628..3872a07ed 100755 --- a/functest/ci/generate_report.py +++ b/functest/ci/generate_report.py @@ -26,7 +26,7 @@ COL_5_LEN = 75 logger = ft_logger.Logger("generate_report").getLogger() -def init(tiers_to_run): +def init(tiers_to_run=[]): test_cases_arr = [] for tier in tiers_to_run: for test in tier.get_tests(): @@ -91,7 +91,7 @@ def print_separator(char="=", delimiter="+"): return str -def main(args): +def main(args=[]): executed_test_cases = args if CONST.IS_CI_RUN: diff --git a/functest/ci/testcases.yaml b/functest/ci/testcases.yaml index bc7ac84ff..5f54b975d 100755 --- a/functest/ci/testcases.yaml +++ b/functest/ci/testcases.yaml @@ -132,7 +132,7 @@ tiers: - name: refstack_defcore - criteria: 'success_rate == 80%' + criteria: 'success_rate == 100%' blocking: false clean_flag: false description: >- @@ -168,7 +168,7 @@ tiers: - name: odl_netvirt criteria: 'success_rate == 100%' - blocking: true + blocking: false clean_flag: false description: >- Test Suite for the OpenDaylight SDN Controller when @@ -436,20 +436,6 @@ tiers: # module: 'functest.opnfv_tests.openstack.tempest.tempest' # class: 'TempestFullParallel' - - name: tempest_defcore - criteria: 'success_rate == 100%' - blocking: false - clean_flag: false - description: >- - This is the set of Tempest test cases created by OpenStack - Interop Working Group for certification purposes. - dependencies: - installer: '' - scenario: 'nosdn-nofeature-ha' - run: - module: 'functest.opnfv_tests.openstack.tempest.tempest' - class: 'TempestDefcore' - - name: tempest_custom criteria: 'success_rate == 100%' blocking: false diff --git a/functest/ci/tier_builder.py b/functest/ci/tier_builder.py index f4c6f70fd..f4c6f70fd 100755..100644 --- a/functest/ci/tier_builder.py +++ b/functest/ci/tier_builder.py diff --git a/functest/ci/tier_handler.py b/functest/ci/tier_handler.py index 6b4864b5b..6b4864b5b 100755..100644 --- a/functest/ci/tier_handler.py +++ b/functest/ci/tier_handler.py diff --git a/functest/core/vnf_base.py b/functest/core/vnf_base.py index 0300dd226..f5e86054f 100644 --- a/functest/core/vnf_base.py +++ b/functest/core/vnf_base.py @@ -52,8 +52,13 @@ class VnfOnBoardingBase(base.TestcaseBase): def execute(self): self.start_time = time.time() # Prepare the test (Create Tenant, User, ...) - self.logger.info("Create VNF Onboarding environment") - self.prepare() + try: + self.logger.info("Create VNF Onboarding environment") + self.prepare() + except Exception: + self.logger.error("Error during VNF Onboarding environment" + + "creation", exc_info=True) + return base.TestcaseBase.EX_TESTCASE_FAILED # Deploy orchestrator try: @@ -179,11 +184,11 @@ class VnfOnBoardingBase(base.TestcaseBase): # TODO see how to use built-in exception from releng module def deploy_vnf(self): self.logger.error("VNF must be deployed") - return base.TestcaseBase.EX_TESTCASE_FAILED + raise Exception("VNF not deployed") def test_vnf(self): self.logger.error("VNF must be tested") - return base.TestcaseBase.EX_TESTCASE_FAILED + raise Exception("VNF not tested") def clean(self): self.logger.info("test cleaning") @@ -232,4 +237,4 @@ class VnfOnBoardingBase(base.TestcaseBase): self.details[part]['status'] = 'FAIL' self.details[part]['result'] = error_msg self.logger.error("Step failure:{}".format(error_msg)) - return base.TestcaseBase.EX_TESTCASE_FAILED + raise Exception(error_msg) diff --git a/functest/opnfv_tests/features/copper.py b/functest/opnfv_tests/features/copper.py index 735b315d2..735b315d2 100755..100644 --- a/functest/opnfv_tests/features/copper.py +++ b/functest/opnfv_tests/features/copper.py diff --git a/functest/opnfv_tests/features/doctor.py b/functest/opnfv_tests/features/doctor.py index 4d295a674..4d295a674 100755..100644 --- a/functest/opnfv_tests/features/doctor.py +++ b/functest/opnfv_tests/features/doctor.py diff --git a/functest/opnfv_tests/features/domino.py b/functest/opnfv_tests/features/domino.py index b36220fa0..b36220fa0 100755..100644 --- a/functest/opnfv_tests/features/domino.py +++ b/functest/opnfv_tests/features/domino.py diff --git a/functest/opnfv_tests/features/odl_sfc.py b/functest/opnfv_tests/features/odl_sfc.py index 3b68d4204..431cd47e4 100644 --- a/functest/opnfv_tests/features/odl_sfc.py +++ b/functest/opnfv_tests/features/odl_sfc.py @@ -8,13 +8,15 @@ # http://www.apache.org/licenses/LICENSE-2.0 # import functest.core.feature_base as base +from sfc.tests.functest import run_tests class OpenDaylightSFC(base.FeatureBase): def __init__(self): super(OpenDaylightSFC, self).__init__(project='sfc', - case='functest-odl-sfc"', + case='functest-odl-sfc', repo='dir_repo_sfc') - dir_sfc_functest = '{}/sfc/tests/functest'.format(self.repo) - self.cmd = 'cd %s && python ./run_tests.py' % dir_sfc_functest + + def execute(self): + return run_tests.main() diff --git a/functest/opnfv_tests/features/promise.py b/functest/opnfv_tests/features/promise.py index 15636fbfe..15636fbfe 100755..100644 --- a/functest/opnfv_tests/features/promise.py +++ b/functest/opnfv_tests/features/promise.py diff --git a/functest/opnfv_tests/features/sdnvpn.py b/functest/opnfv_tests/features/sdnvpn.py index 1919a03c2..1919a03c2 100755..100644 --- a/functest/opnfv_tests/features/sdnvpn.py +++ b/functest/opnfv_tests/features/sdnvpn.py diff --git a/functest/opnfv_tests/features/security_scan.py b/functest/opnfv_tests/features/security_scan.py index 58f0ec748..58f0ec748 100755..100644 --- a/functest/opnfv_tests/features/security_scan.py +++ b/functest/opnfv_tests/features/security_scan.py diff --git a/functest/opnfv_tests/mano/orchestra.py b/functest/opnfv_tests/mano/orchestra.py index fd5e40d05..fd5e40d05 100755..100644 --- a/functest/opnfv_tests/mano/orchestra.py +++ b/functest/opnfv_tests/mano/orchestra.py diff --git a/functest/opnfv_tests/openstack/healthcheck/healthcheck.sh b/functest/opnfv_tests/openstack/healthcheck/healthcheck.sh index 7fa957c01..7fa957c01 100755..100644 --- a/functest/opnfv_tests/openstack/healthcheck/healthcheck.sh +++ b/functest/opnfv_tests/openstack/healthcheck/healthcheck.sh diff --git a/functest/opnfv_tests/openstack/refstack_client/defcore_201608.txt b/functest/opnfv_tests/openstack/refstack_client/defcore.txt index 26eddafcb..be8fd8998 100644 --- a/functest/opnfv_tests/openstack/refstack_client/defcore_201608.txt +++ b/functest/opnfv_tests/openstack/refstack_client/defcore.txt @@ -77,7 +77,7 @@ tempest.api.compute.servers.test_servers_negative.ServersNegativeTestJSON.test_u tempest.api.compute.test_quotas.QuotasTestJSON.test_get_default_quotas[id-9bfecac7-b966-4f47-913f-1a9e2c12134a] tempest.api.compute.test_quotas.QuotasTestJSON.test_get_quotas[id-f1ef0a97-dbbb-4cca-adc5-c9fbc4f76107] tempest.api.compute.test_versions.TestVersions.test_list_api_versions[id-6c0a0990-43b6-4529-9b61-5fd8daf7c55c] -tempest.api.compute.volumes.test_attach_volume.AttachVolumeTestJSON.test_attach_detach_volume[id-52e9045a-e90d-4c0d-9087-79d657faffff] +# tempest.api.compute.volumes.test_attach_volume.AttachVolumeTestJSON.test_attach_detach_volume[id-52e9045a-e90d-4c0d-9087-79d657faffff] tempest.api.compute.volumes.test_attach_volume.AttachVolumeTestJSON.test_list_get_volume_attachments[id-7fa563fe-f0f7-43eb-9e22-a1ece036b513] tempest.api.identity.v3.TestApiDiscovery.test_api_media_types[id-657c1970-4722-4189-8831-7325f3bc4265] tempest.api.identity.v3.TestApiDiscovery.test_api_version_resources[id-b9232f5e-d9e5-4d97-b96c-28d3db4de1bd] diff --git a/functest/opnfv_tests/openstack/refstack_client/refstack_client.py b/functest/opnfv_tests/openstack/refstack_client/refstack_client.py index c9f0f2752..7d4c568a9 100755 --- a/functest/opnfv_tests/openstack/refstack_client/refstack_client.py +++ b/functest/opnfv_tests/openstack/refstack_client/refstack_client.py @@ -129,10 +129,10 @@ class RefstackClient(testcase_base.TestcaseBase): num_executed = int(num_tests) - int(num_skipped) success_rate = 100 * int(num_success) / int(num_executed) - self.details = {"num_tests": int(num_tests), - "num_failures": int(num_failures), + self.details = {"tests": int(num_tests), + "failures": int(num_failures), "success": success_testcases, - "failed": failed_testcases, + "errors": failed_testcases, "skipped": skipped_testcases} except Exception: success_rate = 0 diff --git a/functest/opnfv_tests/vnf/ims/cloudify_ims.py b/functest/opnfv_tests/vnf/ims/cloudify_ims.py index 2ced92e9d..f7dfd532f 100644 --- a/functest/opnfv_tests/vnf/ims/cloudify_ims.py +++ b/functest/opnfv_tests/vnf/ims/cloudify_ims.py @@ -203,7 +203,7 @@ class ImsVnf(vnf_base.VnfOnBoardingBase): flavor_exist, flavor_id = os_utils.get_or_create_flavor( "m1.small", self.vnf['requirements']['ram_min'], - '20', + '30', '1', public=True) self.logger.debug("Flavor id: %s" % flavor_id) @@ -261,6 +261,9 @@ class ImsVnf(vnf_base.VnfOnBoardingBase): dns_ip = dep_outputs.json()['outputs']['dns_ip'] ellis_ip = dep_outputs.json()['outputs']['ellis_ip'] + self.logger.debug("DNS ip : %s" % dns_ip) + self.logger.debug("ELLIS ip : %s" % ellis_ip) + ellis_url = "http://" + ellis_ip + "/" url = ellis_url + "accounts" @@ -270,9 +273,11 @@ class ImsVnf(vnf_base.VnfOnBoardingBase): "signup_code": "secret"} rq = requests.post(url, data=params) - i = 20 + i = 30 while rq.status_code != 201 and i > 0: rq = requests.post(url, data=params) + self.logger.debug("Account creation http status code: %s" + % rq.status_code) i = i - 1 time.sleep(10) @@ -281,8 +286,7 @@ class ImsVnf(vnf_base.VnfOnBoardingBase): rq = requests.post(url, data=params) cookies = rq.cookies else: - self.step_failure("Unable to create an account for number" + - " provision: %s" % rq.json()['reason']) + self.step_failure("Unable to create an account") url = ellis_url + "accounts/" + params['email'] + "/numbers" if cookies != "": @@ -290,6 +294,8 @@ class ImsVnf(vnf_base.VnfOnBoardingBase): i = 24 while rq.status_code != 200 and i > 0: rq = requests.post(url, cookies=cookies) + self.logger.debug("Number creation http status code: %s" + % rq.status_code) i = i - 1 time.sleep(25) diff --git a/functest/opnfv_tests/vnf/ims/cloudify_ims.yaml b/functest/opnfv_tests/vnf/ims/cloudify_ims.yaml index b84ef8fd2..74b9e9580 100644 --- a/functest/opnfv_tests/vnf/ims/cloudify_ims.yaml +++ b/functest/opnfv_tests/vnf/ims/cloudify_ims.yaml @@ -6,7 +6,7 @@ cloudify: url: https://github.com/boucherv-orange/cloudify-manager-blueprints.git branch: '3.3.1-build' requirements: - ram_min: 4000 + ram_min: 4096 os_image: centos_7 inputs: keystone_username: "" @@ -29,7 +29,7 @@ clearwater: branch: stable deployment_name: clearwater-opnfv requirements: - ram_min: 2000 + ram_min: 2048 os_image: ubuntu_14.04 inputs: image_id: '' diff --git a/functest/opnfv_tests/vnf/ims/opera_ims.py b/functest/opnfv_tests/vnf/ims/opera_ims.py index 7ead401fe..7ead401fe 100644..100755 --- a/functest/opnfv_tests/vnf/ims/opera_ims.py +++ b/functest/opnfv_tests/vnf/ims/opera_ims.py diff --git a/functest/opnfv_tests/vnf/ims/orchestra_ims.py b/functest/opnfv_tests/vnf/ims/orchestra_ims.py index 42b218e62..d13fe8fe8 100644..100755 --- a/functest/opnfv_tests/vnf/ims/orchestra_ims.py +++ b/functest/opnfv_tests/vnf/ims/orchestra_ims.py @@ -245,7 +245,7 @@ class ImsVnf(vnf_base.VnfOnBoardingBase): % (self.imagename, network_id, userdata)) instance = os_utils.create_instance_and_wait_for_active( - "m1.medium", + "orchestra", os_utils.get_image_id(glance_client, self.imagename), network_id, "orchestra-openbaton", @@ -308,12 +308,15 @@ class ImsVnf(vnf_base.VnfOnBoardingBase): if self.ob_projectid == "": self.step_failure("Default project id was not found!") + creds = os_utils.get_credentials() + self.logger.info("PoP creds: %s" % creds) + vim_json = { "name": "vim-instance", - "authUrl": os_utils.get_credentials().get("auth_url"), - "tenant": os_utils.get_credentials().get("tenant_name"), - "username": os_utils.get_credentials().get("username"), - "password": os_utils.get_credentials().get("password"), + "authUrl": creds.get("auth_url"), + "tenant": os.environ.get("OS_PROJECT_ID"), + "username": creds.get("username"), + "password": creds.get("password"), "securityGroups": [ "default", "orchestra-sec-group" diff --git a/functest/opnfv_tests/vnf/ims/orchestra_ims.yaml b/functest/opnfv_tests/vnf/ims/orchestra_ims.yaml index 86d6e604a..5923a775a 100644 --- a/functest/opnfv_tests/vnf/ims/orchestra_ims.yaml +++ b/functest/opnfv_tests/vnf/ims/orchestra_ims.yaml @@ -2,8 +2,8 @@ tenant_images: ubuntu_14.04: http://cloud-images.ubuntu.com/trusty/current/trusty-server-cloudimg-amd64-disk1.img openims: http://marketplace.openbaton.org:8082/api/v1/images/52e2ccc0-1dce-4663-894d-28aab49323aa/img openbaton: - bootstrap_link: http://get.openbaton.org/bootstrap - bootstrap_config_link: http://get.openbaton.org/bootstrap-config-file + bootstrap_link: http://get.openbaton.org/bootstraps/bootstrap_3.2.0_opnfv/bootstrap + bootstrap_config_link: http://get.openbaton.org/bootstraps/bootstrap_3.2.0_opnfv/bootstrap-config-file marketplace_link: http://marketplace.openbaton.org:8082/api/v1/nsds/fokus/OpenImsCore/3.2.0/json imagename: ubuntu_14.04 vIMS: diff --git a/functest/opnfv_tests/vnf/router/__init__.py b/functest/opnfv_tests/vnf/router/__init__.py index e69de29bb..e69de29bb 100755..100644 --- a/functest/opnfv_tests/vnf/router/__init__.py +++ b/functest/opnfv_tests/vnf/router/__init__.py diff --git a/functest/opnfv_tests/vnf/router/vyos_vrouter.py b/functest/opnfv_tests/vnf/router/vyos_vrouter.py index 94a3ecfd8..94a3ecfd8 100755..100644 --- a/functest/opnfv_tests/vnf/router/vyos_vrouter.py +++ b/functest/opnfv_tests/vnf/router/vyos_vrouter.py diff --git a/functest/tests/unit/ci/test_generate_report.py b/functest/tests/unit/ci/test_generate_report.py new file mode 100644 index 000000000..2225586f2 --- /dev/null +++ b/functest/tests/unit/ci/test_generate_report.py @@ -0,0 +1,129 @@ +#!/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_run_tests.py b/functest/tests/unit/ci/test_run_tests.py new file mode 100644 index 000000000..021406109 --- /dev/null +++ b/functest/tests/unit/ci/test_run_tests.py @@ -0,0 +1,192 @@ +#!/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 unittest +import logging + +import mock + +from functest.ci import run_tests +from functest.utils.constants import CONST + + +class RunTestsTesting(unittest.TestCase): + + logging.disable(logging.CRITICAL) + + def setUp(self): + self.sep = 'test_sep' + self.creds = {'OS_AUTH_URL': 'http://test_ip:test_port/v2.0', + 'OS_USERNAME': 'test_os_username', + 'OS_TENANT_NAME': 'test_tenant', + 'OS_PASSWORD': 'test_password'} + self.test = {'test_name': 'test_name'} + self.tier = mock.Mock() + attrs = {'get_name.return_value': 'test_tier', + 'get_tests.return_value': ['test1', 'test2'], + 'get_ci_loop.return_value': 'test_ci_loop', + 'get_test_names.return_value': ['test1', 'test2']} + self.tier.configure_mock(**attrs) + + self.tiers = mock.Mock() + attrs = {'get_tiers.return_value': [self.tier]} + self.tiers.configure_mock(**attrs) + + @mock.patch('functest.ci.run_tests.logger.info') + def test_print_separator(self, mock_logger_info): + run_tests.print_separator(self.sep) + mock_logger_info.assert_called_once_with(self.sep * 44) + + @mock.patch('functest.ci.run_tests.logger.error') + def test_source_rc_file_missing_file(self, mock_logger_error): + with mock.patch('functest.ci.run_tests.os.path.isfile', + return_value=False), \ + self.assertRaises(Exception): + run_tests.source_rc_file() + + @mock.patch('functest.ci.run_tests.logger.debug') + def test_source_rc_file_default(self, mock_logger_debug): + with mock.patch('functest.ci.run_tests.os.path.isfile', + return_value=True), \ + mock.patch('functest.ci.run_tests.os_utils.source_credentials', + return_value=self.creds): + run_tests.source_rc_file() + + @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) + + @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]) + + def test_get_run_dict_if_defined_default(self): + mock_obj = mock.Mock() + with mock.patch('functest.ci.run_tests.' + 'ft_utils.get_dict_by_test', + return_value={'run': mock_obj}): + self.assertEqual(run_tests.get_run_dict('test_name'), + mock_obj) + + @mock.patch('functest.ci.run_tests.logger.error') + def test_get_run_dict_if_defined_missing_config_option(self, + mock_logger_error): + with mock.patch('functest.ci.run_tests.' + 'ft_utils.get_dict_by_test', + return_value=None): + testname = 'test_name' + self.assertEqual(run_tests.get_run_dict(testname), + None) + mock_logger_error.assert_called_once_with("Cannot get {}'s config " + "options" + .format(testname)) + + with mock.patch('functest.ci.run_tests.' + 'ft_utils.get_dict_by_test', + return_value={}): + testname = 'test_name' + self.assertEqual(run_tests.get_run_dict(testname), + None) + + @mock.patch('functest.ci.run_tests.logger.exception') + def test_get_run_dict_if_defined_exception(self, + mock_logger_except): + with mock.patch('functest.ci.run_tests.' + 'ft_utils.get_dict_by_test', + side_effect=Exception): + testname = 'test_name' + self.assertEqual(run_tests.get_run_dict(testname), + None) + mock_logger_except.assert_called_once_with("Cannot get {}'s config" + " options" + .format(testname)) + + def test_run_tests_import_test_class_exception(self): + mock_test = mock.Mock() + args = {'get_name': 'test_name', + 'needs_clean': False} + mock_test.configure_mock(**args) + with mock.patch('functest.ci.run_tests.print_separator'),\ + mock.patch('functest.ci.run_tests.source_rc_file'), \ + mock.patch('functest.ci.run_tests.get_run_dict', + return_value=None), \ + self.assertRaises(Exception) as context: + run_tests.run_test(mock_test, 'tier_name') + msg = "Cannot import the class for the test case." + self.assertTrue(msg in context) + + @mock.patch('functest.ci.run_tests.logger.info') + def test_run_tier_default(self, mock_logger_info): + with mock.patch('functest.ci.run_tests.print_separator'), \ + mock.patch('functest.ci.run_tests.run_test') as mock_method: + run_tests.run_tier(self.tier) + mock_method.assert_any_call('test1', 'test_tier') + mock_method.assert_any_call('test2', 'test_tier') + self.assertTrue(mock_logger_info.called) + + @mock.patch('functest.ci.run_tests.logger.info') + def test_run_tier_missing_test(self, mock_logger_info): + with mock.patch('functest.ci.run_tests.print_separator'): + self.tier.get_tests.return_value = None + self.assertEqual(run_tests.run_tier(self.tier), 0) + self.assertTrue(mock_logger_info.called) + + @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' + 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_main_failed(self): + kwargs = {'test': 'test_name', 'noclean': True, 'report': True} + mock_obj = mock.Mock() + args = {'get_tier.return_value': False, + 'get_test.return_value': False} + mock_obj.configure_mock(**args) + + with mock.patch('functest.ci.run_tests.tb.TierBuilder'), \ + mock.patch('functest.ci.run_tests.source_rc_file', + side_effect=Exception): + self.assertEqual(run_tests.main(**kwargs), + run_tests.Result.EX_ERROR) + + with mock.patch('functest.ci.run_tests.tb.TierBuilder', + return_value=mock_obj), \ + mock.patch('functest.ci.run_tests.source_rc_file', + side_effect=Exception): + self.assertEqual(run_tests.main(**kwargs), + run_tests.Result.EX_ERROR) + + +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 new file mode 100644 index 000000000..48c94a57d --- /dev/null +++ b/functest/tests/unit/ci/test_tier_builder.py @@ -0,0 +1,83 @@ +#!/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.ci import tier_builder + + +class TierBuilderTesting(unittest.TestCase): + + logging.disable(logging.CRITICAL) + + def setUp(self): + self.dependency = {'installer': 'test_installer', + 'scenario': 'test_scenario'} + + self.testcase = {'dependencies': self.dependency, + 'name': 'test_name', + 'criteria': 'test_criteria', + 'blocking': 'test_blocking', + 'clean_flag': 'test_clean_flag', + 'description': 'test_desc'} + + self.dic_tier = {'name': 'test_tier', + 'order': 'test_order', + 'ci_loop': 'test_ci_loop', + 'description': 'test_desc', + 'testcases': [self.testcase]} + + self.mock_yaml = mock.Mock() + attrs = {'get.return_value': [self.dic_tier]} + self.mock_yaml.configure_mock(**attrs) + + with mock.patch('functest.ci.tier_builder.yaml.safe_load', + return_value=self.mock_yaml), \ + mock.patch('__builtin__.open', mock.mock_open()): + self.tierbuilder = tier_builder.TierBuilder('test_installer', + 'test_scenario', + 'testcases_file') + self.tier_obj = self.tierbuilder.tier_objects[0] + + def test_get_tiers(self): + self.assertEqual(self.tierbuilder.get_tiers(), + [self.tier_obj]) + + def test_get_tier_names(self): + self.assertEqual(self.tierbuilder.get_tier_names(), + ['test_tier']) + + def test_get_tier_present_tier(self): + self.assertEqual(self.tierbuilder.get_tier('test_tier'), + self.tier_obj) + + def test_get_tier_missing_tier(self): + self.assertEqual(self.tierbuilder.get_tier('test_tier2'), + None) + + def test_get_test_present_test(self): + self.assertEqual(self.tierbuilder.get_test('test_name'), + self.tier_obj.get_test('test_name')) + + def test_get_test_missing_test(self): + self.assertEqual(self.tierbuilder.get_test('test_name2'), + None) + + def test_get_tests_present_tier(self): + self.assertEqual(self.tierbuilder.get_tests('test_tier'), + self.tier_obj.tests_array) + + def test_get_tests_missing_tier(self): + self.assertEqual(self.tierbuilder.get_tests('test_tier2'), + 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 new file mode 100644 index 000000000..01d99d7e7 --- /dev/null +++ b/functest/tests/unit/ci/test_tier_handler.py @@ -0,0 +1,128 @@ +#!/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.ci import tier_handler + + +class TierHandlerTesting(unittest.TestCase): + + logging.disable(logging.CRITICAL) + + def setUp(self): + self.test = mock.Mock() + attrs = {'get_name.return_value': 'test_name'} + self.test.configure_mock(**attrs) + + self.mock_depend = mock.Mock() + attrs = {'get_scenario.return_value': 'test_scenario', + 'get_installer.return_value': 'test_installer'} + self.mock_depend.configure_mock(**attrs) + + self.tier = tier_handler.Tier('test_tier', + 'test_order', + 'test_ci_loop', + description='test_desc') + self.testcase = tier_handler.TestCase('test_name', + self.mock_depend, + 'test_criteria', + 'test_blocking', + 'test_clean_flag', + description='test_desc') + + self.dependency = tier_handler.Dependency('test_installer', + 'test_scenario') + + def test_add_test(self): + self.tier.add_test(self.test) + self.assertEqual(self.tier.tests_array, + [self.test]) + + def test_get_tests(self): + self.tier.tests_array = [self.test] + self.assertEqual(self.tier.get_tests(), + [self.test]) + + def test_get_test_names(self): + self.tier.tests_array = [self.test] + self.assertEqual(self.tier.get_test_names(), + ['test_name']) + + def test_get_test(self): + self.tier.tests_array = [self.test] + with mock.patch.object(self.tier, 'is_test', + return_value=True): + self.assertEqual(self.tier.get_test('test_name'), + self.test) + + def test_get_test_missing_test(self): + self.tier.tests_array = [self.test] + with mock.patch.object(self.tier, 'is_test', + return_value=False): + self.assertEqual(self.tier.get_test('test_name'), + None) + + def test_get_name(self): + self.assertEqual(self.tier.get_name(), + 'test_tier') + + def test_get_order(self): + self.assertEqual(self.tier.get_order(), + 'test_order') + + def test_get_ci_loop(self): + self.assertEqual(self.tier.get_ci_loop(), + 'test_ci_loop') + + def test_testcase_is_none_present_item(self): + self.assertEqual(tier_handler.TestCase.is_none("item"), + False) + + def test_testcase_is_none_missing_item(self): + self.assertEqual(tier_handler.TestCase.is_none(None), + True) + + def test_testcase_is_compatible(self): + self.assertEqual(self.testcase.is_compatible('test_installer', + 'test_scenario'), + True) + + def test_testcase_is_compatible_missing_installer_scenario(self): + self.assertEqual(self.testcase.is_compatible('missing_installer', + 'test_scenario'), + False) + self.assertEqual(self.testcase.is_compatible('test_installer', + 'missing_scenario'), + False) + + def test_testcase_get_name(self): + self.assertEqual(self.tier.get_name(), + 'test_tier') + + def test_testcase_get_criteria(self): + self.assertEqual(self.tier.get_order(), + 'test_order') + + def test_testcase_is_blocking(self): + self.assertEqual(self.tier.get_ci_loop(), + 'test_ci_loop') + + def test_dependency_get_installer(self): + self.assertEqual(self.dependency.get_installer(), + 'test_installer') + + def test_dependency_get_scenario(self): + self.assertEqual(self.dependency.get_scenario(), + 'test_scenario') + + +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 index 25a74b7c9..1680f03f5 100644 --- a/functest/tests/unit/core/test_vnf_base.py +++ b/functest/tests/unit/core/test_vnf_base.py @@ -8,11 +8,9 @@ # http://www.apache.org/licenses/LICENSE-2.0 import logging -import mock import unittest from functest.core import vnf_base -from functest.core import testcase_base class VnfBaseTesting(unittest.TestCase): @@ -37,17 +35,15 @@ class VnfBaseTesting(unittest.TestCase): "result": "", "duration": 5}} - @mock.patch('logging.Logger.error') - def test_deploy_vnf_unimplemented(self, mock): - self.assertEqual(self.test.deploy_vnf(), - testcase_base.TestcaseBase.EX_TESTCASE_FAILED) - mock.assert_called_with('VNF must be deployed') - - @mock.patch('logging.Logger.error') - def test_test_vnf_unimplemented(self, mock): - self.assertEqual(self.test.test_vnf(), - testcase_base.TestcaseBase.EX_TESTCASE_FAILED) - mock.assert_called_with('VNF must be tested') + 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) diff --git a/functest/tests/unit/utils/test_functest_utils.py b/functest/tests/unit/utils/test_functest_utils.py index 8bfdb5e49..eb241e5d0 100644 --- a/functest/tests/unit/utils/test_functest_utils.py +++ b/functest/tests/unit/utils/test_functest_utils.py @@ -33,6 +33,7 @@ class FunctestUtilsTesting(unittest.TestCase): self.installer = 'test_installer' self.scenario = 'test_scenario' self.build_tag = 'jenkins-functest-fuel-opnfv-jump-2-daily-master-190' + self.build_tag_week = 'jenkins-functest-fuel-baremetal-weekly-master-8' self.version = 'master' self.node_name = 'test_node_name' self.project = 'test_project' @@ -152,11 +153,21 @@ class FunctestUtilsTesting(unittest.TestCase): self.scenario) @mock.patch('functest.utils.functest_utils.get_build_tag') - def test_get_version_default(self, mock_get_build_tag): + def test_get_version_daily_job(self, mock_get_build_tag): mock_get_build_tag.return_value = self.build_tag self.assertEqual(functest_utils.get_version(), self.version) @mock.patch('functest.utils.functest_utils.get_build_tag') + def test_get_version_weekly_job(self, mock_get_build_tag): + mock_get_build_tag.return_value = self.build_tag_week + self.assertEqual(functest_utils.get_version(), self.version) + + @mock.patch('functest.utils.functest_utils.get_build_tag') + def test_get_version_with_dummy_build_tag(self, mock_get_build_tag): + mock_get_build_tag.return_value = 'whatever' + self.assertEqual(functest_utils.get_version(), 'unknown') + + @mock.patch('functest.utils.functest_utils.get_build_tag') def test_get_version_unknown(self, mock_get_build_tag): mock_get_build_tag.return_value = "unknown_build_tag" self.assertEqual(functest_utils.get_version(), "unknown") @@ -284,25 +295,6 @@ class FunctestUtilsTesting(unittest.TestCase): def test_push_results_to_db_missing_buildtag(self): self._test_push_results_to_db_missing_env('BUILD_TAG') - def test_push_results_to_db_incorrect_buildtag(self): - dic = self._get_env_dict(None) - dic['BUILD_TAG'] = 'incorrect_build_tag' - with mock.patch('functest.utils.functest_utils.get_db_url', - return_value=self.db_url), \ - mock.patch.dict(os.environ, - dic, - clear=True), \ - mock.patch('functest.utils.functest_utils.logger.error') \ - as mock_logger_error: - self.assertFalse(functest_utils. - push_results_to_db(self.project, self.case_name, - self.start_date, - self.stop_date, - self.criteria, self.details)) - mock_logger_error.assert_called_once_with("Please fix BUILD_TAG" - " env var: incorrect_" - "build_tag") - def test_push_results_to_db_request_post_failed(self): dic = self._get_env_dict(None) with mock.patch('functest.utils.functest_utils.get_db_url', diff --git a/functest/tests/unit/utils/test_openstack_utils.py b/functest/tests/unit/utils/test_openstack_utils.py index ef3764cc5..f51a4991c 100644 --- a/functest/tests/unit/utils/test_openstack_utils.py +++ b/functest/tests/unit/utils/test_openstack_utils.py @@ -28,7 +28,8 @@ class OSUtilsTesting(unittest.TestCase): 'OS_PROJECT_DOMAIN_NAME': os_prefix + 'project_domain_name', 'OS_PROJECT_NAME': os_prefix + 'project_name', 'OS_ENDPOINT_TYPE': os_prefix + 'endpoint_type', - 'OS_REGION_NAME': os_prefix + 'region_name'} + 'OS_REGION_NAME': os_prefix + 'region_name', + 'OS_CACERT': os_prefix + 'https_cacert'} def _get_os_env_vars(self): return {'username': 'test_username', 'password': 'test_password', @@ -37,7 +38,8 @@ class OSUtilsTesting(unittest.TestCase): 'project_domain_name': 'test_project_domain_name', 'project_name': 'test_project_name', 'endpoint_type': 'test_endpoint_type', - 'region_name': 'test_region_name'} + 'region_name': 'test_region_name', + 'https_cacert': 'test_https_cacert'} def setUp(self): self.env_vars = ['OS_AUTH_URL', 'OS_USERNAME', 'OS_PASSWORD'] @@ -299,7 +301,7 @@ class OSUtilsTesting(unittest.TestCase): 'OS_PROJECT_DOMAIN_NAME']) self.assertEqual(openstack_utils.get_rc_env_vars(), exp_resp) - @mock.patch('functest.utils.openstack_utils.get_rc_env_vars') + @mock.patch('functest.utils.openstack_utils') def test_check_credentials_missing_env(self, mock_get_rc_env): exp_resp = self.env_vars exp_resp.extend(['OS_TENANT_NAME']) diff --git a/functest/utils/decorators.py b/functest/utils/decorators.py index 99bcef3e6..276235d96 100644 --- a/functest/utils/decorators.py +++ b/functest/utils/decorators.py @@ -1,6 +1,8 @@ #!/usr/bin/env python +import errno import mock +import os import requests.sessions import urlparse @@ -10,7 +12,12 @@ def can_dump_request_to_file(method): def dump_preparedrequest(request, **kwargs): parseresult = urlparse.urlparse(request.url) if parseresult.scheme == "file": - with open(parseresult.path.replace('/results', ''), 'a') as f: + try: + os.makedirs(parseresult.path) + except OSError as e: + if e.errno != errno.EEXIST: + raise + with open(os.path.join(parseresult.path, 'dump.txt'), 'a') as f: headers = "" for key in request.headers: headers += key + " " + request.headers[key] + "\n" diff --git a/functest/utils/functest_logger.py b/functest/utils/functest_logger.py index 022211cb7..022211cb7 100755..100644 --- a/functest/utils/functest_logger.py +++ b/functest/utils/functest_logger.py diff --git a/functest/utils/functest_utils.py b/functest/utils/functest_utils.py index e5e755d7f..7cc5029d9 100644 --- a/functest/utils/functest_utils.py +++ b/functest/utils/functest_utils.py @@ -111,12 +111,13 @@ def get_version(): # if launched through CI the build tag has the following format # jenkins-<project>-<installer>-<pod>-<job>-<branch>-<id> # e.g. jenkins-functest-fuel-opnfv-jump-2-daily-master-190 + # jenkins-functest-fuel-baremetal-weekly-master-8 # use regex to match branch info - rule = "daily-(.+?)-[0-9]*" + rule = "(dai|week)ly-(.+?)-[0-9]*" build_tag = get_build_tag() m = re.search(rule, build_tag) if m: - return m.group(1) + return m.group(2) else: return "unknown" @@ -156,8 +157,6 @@ def get_db_url(): # if TEST_DB_URL declared in env variable, use it! db_url = os.environ['TEST_DB_URL'] except KeyError: - logger.info("DB URL not declared as env variable," - "use local configuration") db_url = get_functest_config('results.test_db_url') return db_url @@ -208,13 +207,7 @@ def push_results_to_db(project, case_name, except KeyError as e: logger.error("Please set env var: " + str(e)) return False - rule = "daily-(.+?)-[0-9]*" - m = re.search(rule, build_tag) - if m: - version = m.group(1) - else: - logger.error("Please fix BUILD_TAG env var: " + build_tag) - return False + version = get_version() test_start = dt.fromtimestamp(start_date).strftime('%Y-%m-%d %H:%M:%S') test_stop = dt.fromtimestamp(stop_date).strftime('%Y-%m-%d %H:%M:%S') diff --git a/functest/utils/openstack_utils.py b/functest/utils/openstack_utils.py index e33af63b4..ffc870f62 100755..100644 --- a/functest/utils/openstack_utils.py +++ b/functest/utils/openstack_utils.py @@ -82,7 +82,8 @@ def get_env_cred_dict(): 'OS_PROJECT_DOMAIN_NAME': 'project_domain_name', 'OS_PROJECT_NAME': 'project_name', 'OS_ENDPOINT_TYPE': 'endpoint_type', - 'OS_REGION_NAME': 'region_name' + 'OS_REGION_NAME': 'region_name', + 'OS_CACERT': 'https_cacert' } return env_cred_dict @@ -149,6 +150,11 @@ def get_credentials_for_rally(): if region_name is not None: cred_key = env_cred_dict.get('OS_REGION_NAME') rally_conf[cred_key] = region_name + + cacert = os.getenv('OS_CACERT') + if cacert is not None: + cred_key = env_cred_dict.get('OS_CACERT') + rally_conf[cred_key] = cacert return rally_conf @@ -168,7 +174,14 @@ def get_endpoint(service_type, endpoint_type='publicURL'): def get_session(other_creds={}): auth = get_session_auth(other_creds) - return session.Session(auth=auth) + cacert = os.getenv('OS_CACERT') + if cacert is not None: + if not os.path.isfile(cacert): + raise Exception("The 'OS_CACERT' environment" + "variable is set to %s but the file" + "does not exist.", cacert) + + return session.Session(auth=auth, verify=cacert) # ********************************************* |