aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--docker/Dockerfile6
-rw-r--r--docker/Dockerfile.aarch642
-rwxr-xr-xdocker/add_images.sh17
-rw-r--r--docs/internship/testapi_evolution/index.rst70
-rw-r--r--docs/release/release-notes/functest-release.rst (renamed from docs/release-notes/functest-release.rst)0
-rw-r--r--docs/release/release-notes/index.rst (renamed from docs/release-notes/index.rst)0
-rw-r--r--docs/testing/developer/devguide/index.rst (renamed from docs/devguide/index.rst)30
-rw-r--r--docs/testing/developer/internship/security_group/index.rst (renamed from docs/internship/security_group/index.rst)0
-rw-r--r--docs/testing/developer/internship/testapi_evolution/index.rst237
-rw-r--r--docs/testing/developer/internship/unit_tests/index.rst (renamed from docs/internship/unit_tests/index.rst)0
-rw-r--r--docs/testing/developer/internship/vnf_catalog/index.rst (renamed from docs/internship/vnf_catalog/index.rst)0
-rw-r--r--docs/testing/user/configguide/configguide.rst (renamed from docs/configguide/configguide.rst)0
-rw-r--r--docs/testing/user/configguide/index.rst (renamed from docs/configguide/index.rst)0
-rw-r--r--docs/testing/user/userguide/index.rst (renamed from docs/userguide/index.rst)0
-rw-r--r--docs/testing/user/userguide/introduction.rst (renamed from docs/userguide/introduction.rst)0
-rw-r--r--docs/testing/user/userguide/runfunctest.rst (renamed from docs/userguide/runfunctest.rst)2
-rw-r--r--docs/testing/user/userguide/troubleshooting.rst (renamed from docs/userguide/troubleshooting.rst)2
-rw-r--r--functest/ci/config_aarch64_patch.yaml20
-rwxr-xr-xfunctest/ci/config_functest.yaml7
-rwxr-xr-xfunctest/ci/config_patch.yaml6
-rwxr-xr-xfunctest/ci/prepare_env.py107
-rw-r--r--functest/ci/rally_aarch64_patch.conf5
-rwxr-xr-xfunctest/ci/testcases.yaml45
-rw-r--r--functest/opnfv_tests/openstack/rally/scenario/templates/server_with_ports.yaml.template2
-rw-r--r--functest/opnfv_tests/openstack/rally/scenario/templates/server_with_volume.yaml.template2
-rw-r--r--functest/opnfv_tests/openstack/tempest/custom_tests/blacklist.txt19
-rw-r--r--functest/opnfv_tests/openstack/tempest/custom_tests/test_list.txt4
-rw-r--r--functest/opnfv_tests/openstack/tempest/tempest.py6
-rw-r--r--functest/opnfv_tests/vnf/ims/cloudify_ims.py13
-rwxr-xr-xfunctest/opnfv_tests/vnf/router/__init__.py0
-rwxr-xr-xfunctest/opnfv_tests/vnf/router/vyos_vrouter.py33
-rw-r--r--functest/tests/unit/opnfv_tests/vnf/__init__.py0
-rw-r--r--functest/tests/unit/opnfv_tests/vnf/ims/__init__.py0
-rw-r--r--functest/tests/unit/opnfv_tests/vnf/ims/test_clearwater.py54
-rw-r--r--functest/tests/unit/opnfv_tests/vnf/ims/test_cloudify_ims.py542
-rw-r--r--functest/tests/unit/opnfv_tests/vnf/ims/test_orchestrator_cloudify.py122
-rw-r--r--functest/tests/unit/utils/test_openstack_utils.py58
-rwxr-xr-x[-rw-r--r--]functest/utils/config.py20
-rwxr-xr-xfunctest/utils/openstack_utils.py87
-rw-r--r--requirements.txt1
-rwxr-xr-xrun_unit_tests.sh1
-rw-r--r--test-requirements.txt2
42 files changed, 1333 insertions, 189 deletions
diff --git a/docker/Dockerfile b/docker/Dockerfile
index f59e1f73c..de47e157a 100644
--- a/docker/Dockerfile
+++ b/docker/Dockerfile
@@ -19,6 +19,7 @@ ARG ODL_TAG=release/beryllium-sr4
ARG OPENSTACK_TAG=stable/mitaka
ARG KINGBIRD_TAG=0.2.2
ARG VIMS_TAG=stable
+ARG VROUTER_TAG=stable
ARG REPOS_DIR=/home/opnfv/repos
ARG FUNCTEST_BASE_DIR=/home/opnfv/functest
ARG FUNCTEST_CONF_DIR=${FUNCTEST_BASE_DIR}/conf
@@ -99,6 +100,7 @@ RUN git clone --depth 1 -b $TEMPEST_TAG https://github.com/openstack/tempest.git
# other repositories
RUN git clone --depth 1 -b $ODL_TAG https://git.opendaylight.org/gerrit/p/integration/test.git ${REPOS_DIR}/odl_test
RUN git clone --depth 1 -b $VIMS_TAG https://github.com/boucherv-orange/clearwater-live-test ${REPOS_VNFS_DIR}/vims-test
+RUN git clone --depth 1 -b $VROUTER_TAG https://github.com/oolorg/opnfv-functest-vrouter.git ${REPOS_VNFS_DIR}/vrouter
RUN git clone --depth 1 https://github.com/wuwenbin2/OnosSystemTest.git ${REPOS_DIR}/onos
RUN pip install -r ${REPOS_DIR}/rally/requirements.txt
@@ -121,9 +123,7 @@ RUN find ${FUNCTEST_REPO_DIR} -name "*.py" \
RUN /bin/bash ${REPOS_DIR}/parser/tests/parser_install.sh ${REPOS_DIR}
RUN ${REPOS_DIR}/rally/install_rally.sh --yes
-ADD http://download.cirros-cloud.net/0.3.4/cirros-0.3.4-x86_64-disk.img ${FUNCTEST_BASE_DIR}/data/
-ADD http://download.cirros-cloud.net/0.3.4/cirros-0.3.4-x86_64-lxc.tar.gz ${FUNCTEST_BASE_DIR}/data/
-ADD http://205.177.226.237:9999/onosfw/firewall_block_image.img ${FUNCTEST_BASE_DIR}/data/
+RUN /bin/bash ${REPOS_DIR}/functest/docker/add_images.sh
RUN gpg --keyserver hkp://p80.pool.sks-keyservers.net:80 --recv-keys 409B6B1796C275462A1703113804BB82D39DC0E3
RUN curl -L https://get.rvm.io | bash -s stable
diff --git a/docker/Dockerfile.aarch64 b/docker/Dockerfile.aarch64
index bf8e361f0..a469801f3 100644
--- a/docker/Dockerfile.aarch64
+++ b/docker/Dockerfile.aarch64
@@ -117,6 +117,8 @@ RUN find ${FUNCTEST_REPO_DIR} -name "*.py" \
RUN /bin/bash ${REPOS_DIR}/parser/tests/parser_install.sh ${REPOS_DIR}
RUN ${REPOS_DIR}/rally/install_rally.sh --yes
+RUN /bin/bash ${REPOS_DIR}/functest/docker/add_images.sh
+
RUN gpg --keyserver hkp://p80.pool.sks-keyservers.net:80 --recv-keys 409B6B1796C275462A1703113804BB82D39DC0E3
RUN curl -L https://get.rvm.io | bash -s stable
diff --git a/docker/add_images.sh b/docker/add_images.sh
new file mode 100755
index 000000000..af2956c29
--- /dev/null
+++ b/docker/add_images.sh
@@ -0,0 +1,17 @@
+#!/usr/bin/env bash
+#
+# This script downloads the images that are used for testing
+# and places them in the functest docker image
+
+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/
+
+# 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/
diff --git a/docs/internship/testapi_evolution/index.rst b/docs/internship/testapi_evolution/index.rst
deleted file mode 100644
index f2583e2f0..000000000
--- a/docs/internship/testapi_evolution/index.rst
+++ /dev/null
@@ -1,70 +0,0 @@
-=======
-License
-=======
-
-Functest Docs are licensed under a Creative Commons Attribution 4.0
-International License.
-You should have received a copy of the license along with this.
-If not, see <http://creativecommons.org/licenses/by/4.0/>.
-
-==================
-Test API evolution
-==================
-
-Author: Rohit Sakala
-Mentors: S. Feng, J.Lausuch, M.Richomme
-
-Abstract
-========
-
-
-Version history
-===============
-
-+------------+----------+------------------+------------------------+
-| **Date** | **Ver.** | **Author** | **Comment** |
-| | | | |
-+------------+----------+------------------+------------------------+
-| 2016-??-?? | 0.0.1 | Morgan Richomme | Beginning of the |
-| | | (Orange) | Internship |
-+------------+----------+------------------+------------------------+
-
-
-Overview:
-=========
-
-
-
-
-Problem Statement:
-------------------
-
-
-
-Curation Phase
---------------
-
-
-
-
-
-Schedule:
-=========
-
-
-
-+--------------------------+------------------------------------------+
-| **Date** | **Comment** |
-| | |
-+--------------------------+------------------------------------------+
-| December - January | ........ |
-+--------------------------+------------------------------------------+
-| January - february | ........ |
-+--------------------------+------------------------------------------+
-
-
-References:
-===========
-
-.. _`[1]` : https://wiki.opnfv.org/display/DEV/Intern+Project%3A+testapi+evolution
-
diff --git a/docs/release-notes/functest-release.rst b/docs/release/release-notes/functest-release.rst
index 07389bb5b..07389bb5b 100644
--- a/docs/release-notes/functest-release.rst
+++ b/docs/release/release-notes/functest-release.rst
diff --git a/docs/release-notes/index.rst b/docs/release/release-notes/index.rst
index 6c6d18109..6c6d18109 100644
--- a/docs/release-notes/index.rst
+++ b/docs/release/release-notes/index.rst
diff --git a/docs/devguide/index.rst b/docs/testing/developer/devguide/index.rst
index 42ad04451..eee013678 100644
--- a/docs/devguide/index.rst
+++ b/docs/testing/developer/devguide/index.rst
@@ -335,10 +335,6 @@ The API can described as follows. For detailed information, please go to
Authentication: opnfv/api@opnfv
-Please notes that POST/DELETE/PUT operations for test or study purpose via
-swagger website is not allowed, because it will change the real data in
-the database.
-
Version:
+--------+--------------------------+-----------------------------------------+
@@ -503,17 +499,39 @@ Scenarios:
The code of the API is hosted in the releng repository `[6]`_.
+The static documentation of the API can be found at `[17]`_.
The test API has been dockerized and may be installed locally in your
lab. See `[15]`_ for details.
The deployment of the test API has been automated.
A jenkins job manages:
* the unit tests of the test api
- * the cration of a new docker file
+ * the creation of a new docker file
* the deployment of the new test api
* the archive of the old test api
* the backup of the Mongo DB
+Test API Authorization
+~~~~~~~~~~~~~~~~~~~~~~
+
+PUT/DELETE/POST operations of the testapi now require token based authorization. The token needs
+to be added in the request using a header 'X-Auth-Token' for access to the database.
+
+e.g::
+ headers['X-Auth-Token']
+
+The value of the header i.e the token can be accessed in the jenkins environment variable
+*TestApiToken*. The token value is added as a masked password.
+
+.. code-block:: python
+
+ headers['X-Auth-Token'] = os.environ.get('TestApiToken')
+
+The above example is in Python. Token based authentication has been added so that only ci pods
+jenkins job can have access to the database.
+
+Please note that currently token authorization is implemented but is not yet enabled.
+
Automatic reporting
===================
@@ -960,6 +978,8 @@ _`[15]`: https://git.opnfv.org/cgit/releng/tree/utils/test/result_collection_api
_`[16]`: https://git.opnfv.org/cgit/releng/tree/utils/test/scripts/mongo_to_elasticsearch.py
+_`[17]`: http://artifacts.opnfv.org/releng/docs/testapi.html
+
OPNFV main site: http://www.opnfv.org
OPNFV functional test page: https://wiki.opnfv.org/opnfv_functional_testing
diff --git a/docs/internship/security_group/index.rst b/docs/testing/developer/internship/security_group/index.rst
index d1cdbdd8f..d1cdbdd8f 100644
--- a/docs/internship/security_group/index.rst
+++ b/docs/testing/developer/internship/security_group/index.rst
diff --git a/docs/testing/developer/internship/testapi_evolution/index.rst b/docs/testing/developer/internship/testapi_evolution/index.rst
new file mode 100644
index 000000000..6a1cde7df
--- /dev/null
+++ b/docs/testing/developer/internship/testapi_evolution/index.rst
@@ -0,0 +1,237 @@
+=======
+License
+=======
+
+Functest Docs are licensed under a Creative Commons Attribution 4.0
+International License.
+You should have received a copy of the license along with this.
+If not, see <http://creativecommons.org/licenses/by/4.0/>.
+
+==================
+Test API evolution
+==================
+
+Author: Sakala Venkata Krishna Rohit
+Mentors: S. Feng, J.Lausuch, M.Richomme
+
+Abstract
+========
+
+The testapi is used by all the test opnfv projects to report results.
+It is also used to declare projects, test cases and labs. A major refactoring
+has been done in Colorado with the introduction of swagger. The testapi is defined in Functest
+developer guide. The purpose of this project is to add more features to the testapi that automate
+the tasks that are done manually now, though there are tasks other than automation.
+
+Version history
+===============
+
++------------+----------+------------------+------------------------+
+| **Date** | **Ver.** | **Author** | **Comment** |
+| | | | |
++------------+----------+------------------+------------------------+
+| 2016-11-14 | 0.0.1 | Morgan Richomme | Beginning of the |
+| | | (Orange) | Internship |
++------------+----------+------------------+------------------------+
+| 2017-02-17 | 0.0.2 | S.V.K Rohit | End of the Internship |
+| | | (IIIT Hyderabad) | |
++------------+----------+------------------+------------------------+
+
+Overview:
+=========
+
+The internhip time period was from Nov 14th to Feb 17th. The project prosposal page is here `[1]`_.
+The intern project was assigned to Svk Rohit and was mentored by S. Feng, J.Lausuch, M.Richomme.
+The link to the patches submitted is `[2]`_. The internship was successfully completed and the
+documentation is as follows.
+
+Problem Statement:
+------------------
+
+The problem statement could be divided into pending features that needed to be added into testapi
+repo. The following were to be accomplished within the internship time frame.
+
+* **Add verification jenkins job for the testapi code**
+ The purpose of this job is to verify whehter the unit tests are successful or not with the
+ inclusion of the patchset submitted.
+
+* **Automatic update of opnfv/testapi docker image**
+ The docker image of testapi is hosted in the opnfv docker hub. To ensure that the testapi image
+ is always updated with the repository, automatic updation of the image is necessary and a job
+ is triggered whenever a new patch gets merged.
+
+* **Automation deployment of testresults.opnfv.org/test/ website**
+ In the same manner as the docker image of testapi is updated, the testapi website needs to be
+ in sync with the repository code. So, a job has been added to the opnfv jenkins ci for the
+ updation of the testresults website.
+
+* **Generate static documentation of testapi calls**
+ The purpose of this is to give an static/offline view of testapi. If someone wants to have a
+ look at the Restful apis of testapi, he/she does't need to go to the website, he can download
+ a html page and view it anytime.
+
+* **Backup MongoDB of testapi**
+ The mongoDB needs to be backed up every week. Till now it was done manually, but due to this
+ internship, it is now automated using a jenkins job.
+
+* **Add token based authorization to the testapi calls**
+ The token based authorization was implemented to ensure that only ci_pods could access the
+ database. Authentication has been added to only delete/put/post requests.
+
+Curation Phase:
+---------------
+
+The curation phase was the first 3 to 4 weeks of the internship. This phase was to get familiar
+with the testapi code and functionality and propose the solutions/tools for the tasks mentioned
+above. Swagger codegen was choosen out of the four tools proposed `[3]`_ for generating static
+documentaion.
+
+Also, specific amount of time was spent on the script flow of the jenkins jobs. The automatic
+deployment task involves accessing a remote server from inside the jenkins build. The deployment
+had to be done only after the docker image update is done. For these constraints to satisfy, a
+multijob jenkins job was choosen instead of a freestyle job.
+
+Important Links:
+----------------
+
+* MongoDB Backup Link - `[4]`_
+* Static Documentation - `[5]`_
+* TestAPI Token addition to ci_pods - `[6]`_
+
+Schedule:
+=========
+
+The progress and completion of the tasks is described in the below table.
+
++--------------------------+------------------------------------------+
+| **Date** | **Comment** |
+| | |
++--------------------------+------------------------------------------+
+| Nov 14th - Dec 31st | Understand Testapi code and the |
+| | requirements. |
++--------------------------+------------------------------------------+
+| Jan 1st - Jan 7th | Add jenkins job to create static |
+| | documentation and write build scripts. |
++--------------------------+------------------------------------------+
+| Jan 8th - Jan 21st | Add verification jenkins job for unit |
+| | tests. |
++--------------------------+------------------------------------------+
+| Jan 22nd - Jan 28th | Add jenkins job for mongodb backup |
+| | |
++--------------------------+------------------------------------------+
+| Jan 29th - Feb 11th | Enable automatic deployment of |
+| | testresults.opnfv.org/test/ |
++--------------------------+------------------------------------------+
+| Feb 12th - Feb 17th | Add token based authentication |
+| | |
++--------------------------+------------------------------------------+
+
+FAQ's
+=====
+
+This section lists the problems that I have faced and the understanding that I have acquired during
+the internship. This section may help other developers in solving any errors casused because of the
+code written as a part of this internship.
+
+
+Test Api
+--------
+
+What is the difference between defining data_file as "/etc/.." and "etc/.." in setup.cfg ?
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+If in the setup.cfg, it is defined as
+
+[files]
+data_files =
+etc/a.conf = etc/a.conf.sample
+
+then it ends up installed in the /usr/etc/. With this configuration, it would be installed
+correctly within a venv. but when it is defined as
+
+[files]
+data_files =
+/etc/a.conf = etc/a.conf.sample
+
+then it ends up installed on the root of the filesystem instead of properly be installed within the
+venv.
+
+Which attribute does swagger-codegen uses as the title in the generation of document generation ?
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+It uses the nickname of the api call in swagger as the title in the generation of the document
+generation.
+
+Does swagger-codegen take more than one yaml file as input ?
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+No, swagger-codegen only takes one yaml file as input to its jar file. If there more than one yaml
+file, one needs to merge them and give it as an input keeping mind the swagger specs.
+
+
+Jenkins & JJB
+-------------
+
+Which scm macro is used for verification jenkins jobs ?
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+There are two macros for scm one is git-scm and other git-scm-gerrit. git-scm-gerrit is used for
+verification jenkins job.
+
+Does the virtualenv created in one build script exists in other build scripts too ?
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+No, the virtualenv created in one build script only exists in that build script/shell.
+
+What parameters are needed for the scm macros ?
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+Project and Branch are the two parameters needed for scm macros.
+
+What is the directory inside the jenkins build ?
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+The directory of the jenkins build is the directory of the repo. `ls $WORKSPACE` command will give
+you all the contents of the directory.
+
+How to include a bash script in jenkins job yaml file ?
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+An example might be apt here as an answer.
+
+builders:
+ - shell:
+ !include-raw: include-raw001-hello-world.sh
+
+
+How do you make a build server run on a specific machine ?
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+It can be done by defining a label parameter 'SLAVE_LABEL' or in OPNFV , there are macros for each
+server, one can use those parameter macros.
+Ex: opnfv-build-defaults. Note, if we use macro, then no need to define GIT_BASE, but if one uses
+SLAVE_LABEL, one needs to define a parameter GIT_BASE. This is because macro already has GIT_BASE
+defined.
+
+What job style should be used when there is a situation like one build should trigger other builds
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+or when different build scripts need to be run on different machines ?
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+MultiJob style should be used as it has phases where each phase can be taken as a build scipt and
+can have its own parameters by which one can define the SLAVE_LABEL parameter.
+
+References:
+===========
+
+_`[1]` : https://wiki.opnfv.org/display/DEV/Intern+Project%3A+testapi+evolution
+
+_`[2]` : https://gerrit.opnfv.org/gerrit/#/q/status:merged+owner:%22Rohit+Sakala+%253Crohitsakala%2540gmail.com%253E%22
+
+_`[3]` : https://docs.google.com/document/d/1jWwVZ1ZpKgKcOS_zSz2KzX1nwg4BXxzBxcwkesl7krw/edit?usp=sharing
+
+_`[4]` : http://artifacts.opnfv.org/testapibackup.html
+
+_`[5]` : http://artifacts.opnfv.org/releng/docs/testapi.html
+
+_`[6]` : http://artifacts.opnfv.org/functest/docs/devguide/index.html#test-api-authorization
diff --git a/docs/internship/unit_tests/index.rst b/docs/testing/developer/internship/unit_tests/index.rst
index f969aa72d..f969aa72d 100644
--- a/docs/internship/unit_tests/index.rst
+++ b/docs/testing/developer/internship/unit_tests/index.rst
diff --git a/docs/internship/vnf_catalog/index.rst b/docs/testing/developer/internship/vnf_catalog/index.rst
index df7633391..df7633391 100644
--- a/docs/internship/vnf_catalog/index.rst
+++ b/docs/testing/developer/internship/vnf_catalog/index.rst
diff --git a/docs/configguide/configguide.rst b/docs/testing/user/configguide/configguide.rst
index 08e089c2b..08e089c2b 100644
--- a/docs/configguide/configguide.rst
+++ b/docs/testing/user/configguide/configguide.rst
diff --git a/docs/configguide/index.rst b/docs/testing/user/configguide/index.rst
index f12739e31..f12739e31 100644
--- a/docs/configguide/index.rst
+++ b/docs/testing/user/configguide/index.rst
diff --git a/docs/userguide/index.rst b/docs/testing/user/userguide/index.rst
index 9436de2b9..9436de2b9 100644
--- a/docs/userguide/index.rst
+++ b/docs/testing/user/userguide/index.rst
diff --git a/docs/userguide/introduction.rst b/docs/testing/user/userguide/introduction.rst
index 4dfe79375..4dfe79375 100644
--- a/docs/userguide/introduction.rst
+++ b/docs/testing/user/userguide/introduction.rst
diff --git a/docs/userguide/runfunctest.rst b/docs/testing/user/userguide/runfunctest.rst
index b5c7191ca..e7ab84b26 100644
--- a/docs/userguide/runfunctest.rst
+++ b/docs/testing/user/userguide/runfunctest.rst
@@ -174,7 +174,7 @@ To execute a Test Tier or Test Case, the 'run' command is used::
2016-06-30 11:50:31,865 - run_tests - INFO - ============================================
2016-06-30 11:50:31,865 - run_tests - INFO - Running test case 'vping_ssh'...
2016-06-30 11:50:31,865 - run_tests - INFO - ============================================
- 2016-06-30 11:50:32,977 - vping_ssh - INFO - Creating image 'functest-vping' from '/home/opnfv/functest/data/cirros-0.3.4-x86_64-disk.img'...
+ 2016-06-30 11:50:32,977 - vping_ssh - INFO - Creating image 'functest-vping' from '/home/opnfv/functest/data/cirros-0.3.5-x86_64-disk.img'...
2016-06-30 11:50:45,470 - vping_ssh - INFO - Creating neutron network vping-net...
2016-06-30 11:50:47,645 - vping_ssh - INFO - Creating security group 'vPing-sg'...
2016-06-30 11:50:48,843 - vping_ssh - INFO - Using existing Flavor 'm1.small'...
diff --git a/docs/userguide/troubleshooting.rst b/docs/testing/user/userguide/troubleshooting.rst
index 1b7bf9b38..845501916 100644
--- a/docs/userguide/troubleshooting.rst
+++ b/docs/testing/user/userguide/troubleshooting.rst
@@ -100,7 +100,7 @@ In this case, proceed to create it manually. These are some hints::
--protocol tcp --port-range-min 80 --port-range-max 80 --remote-ip-prefix 0.0.0.0/0
The next step is to create the instances. The image used is located in
-*/home/opnfv/functest/data/cirros-0.3.4-x86_64-disk.img* and a Glance image is created
+*/home/opnfv/functest/data/cirros-0.3.5-x86_64-disk.img* and a Glance image is created
with the name **functest-vping**. If booting the instances fails (i.e. the status
is not **ACTIVE**), you can check why it failed by doing::
diff --git a/functest/ci/config_aarch64_patch.yaml b/functest/ci/config_aarch64_patch.yaml
new file mode 100644
index 000000000..9a345e3f7
--- /dev/null
+++ b/functest/ci/config_aarch64_patch.yaml
@@ -0,0 +1,20 @@
+os:
+ general:
+ openstack:
+ image_name: TestVM
+ image_file_name: cirros-d161201-aarch64-disk.img
+ image_password: gocubsgo
+
+ snaps_simple_healthcheck:
+ disk_image: /home/opnfv/functest/data/cirros-d161201-aarch64-disk.img
+ kernel_image: /home/opnfv/functest/data/cirros-d161201-aarch64-kernel
+ ramdisk_image: /home/opnfv/functest/data/cirros-d161201-aarch64-initramfs
+ extra_properties:
+ os_command_line: root=/dev/vdb1 rw rootwait console=tty0 console=ttyS0 console=ttyAMA0
+ hw_video_model: vga
+
+ vping:
+ image_name: TestVM
+
+ doctor:
+ image_name: TestVM
diff --git a/functest/ci/config_functest.yaml b/functest/ci/config_functest.yaml
index a3eebab7b..402e29999 100755
--- a/functest/ci/config_functest.yaml
+++ b/functest/ci/config_functest.yaml
@@ -29,6 +29,7 @@ general:
repo_domino: /home/opnfv/repos/domino
repo_snaps: /home/opnfv/repos/snaps
repo_securityscan: /home/opnfv/repos/securityscanning
+ repo_vrouter: /home/opnfv/repos/vrouter
functest: /home/opnfv/functest
functest_test: /home/opnfv/repos/functest/functest/opnfv_tests
results: /home/opnfv/functest/results
@@ -42,8 +43,8 @@ general:
creds: /home/opnfv/functest/conf/openstack.creds
snapshot_file: /home/opnfv/functest/conf/openstack_snapshot.yaml
- image_name: Cirros-0.3.4
- image_file_name: cirros-0.3.4-x86_64-disk.img
+ image_name: Cirros-0.3.5
+ image_file_name: cirros-0.3.5-x86_64-disk.img
image_disk_format: qcow2
image_username: cirros
image_password: cubswin:)
@@ -66,7 +67,7 @@ general:
testcases_yaml: /home/opnfv/repos/functest/functest/ci/testcases.yaml
healthcheck:
- disk_image: /home/opnfv/functest/data/cirros-0.3.4-x86_64-disk.img
+ disk_image: /home/opnfv/functest/data/cirros-0.3.5-x86_64-disk.img
disk_format: qcow2
wait_time: 60
diff --git a/functest/ci/config_patch.yaml b/functest/ci/config_patch.yaml
index 46064a07f..d984a3f47 100755
--- a/functest/ci/config_patch.yaml
+++ b/functest/ci/config_patch.yaml
@@ -1,12 +1,12 @@
lxd:
general:
openstack:
- image_name: Cirros-0.3.4
- image_file_name: cirros-0.3.4-x86_64-lxc.tar.gz
+ image_name: Cirros-0.3.5
+ image_file_name: cirros-0.3.5-x86_64-lxc.tar.gz
image_disk_format: raw
healthcheck:
- disk_image: /home/opnfv/functest/data/cirros-0.3.4-x86_64-lxc.tar.gz
+ disk_image: /home/opnfv/functest/data/cirros-0.3.5-x86_64-lxc.tar.gz
disk_format: raw
fdio:
general:
diff --git a/functest/ci/prepare_env.py b/functest/ci/prepare_env.py
index 5a9f99cb6..724ea14df 100755
--- a/functest/ci/prepare_env.py
+++ b/functest/ci/prepare_env.py
@@ -12,6 +12,7 @@ import os
import re
import subprocess
import sys
+import fileinput
import yaml
@@ -27,14 +28,19 @@ actions = ['start', 'check']
""" logging configuration """
logger = ft_logger.Logger("prepare_env").getLogger()
-
+handler = None
+# set the architecture to default
+pod_arch = None
+arch_filter = ['aarch64']
CONFIG_FUNCTEST_PATH = CONST.CONFIG_FUNCTEST_YAML
CONFIG_PATCH_PATH = os.path.join(os.path.dirname(
CONFIG_FUNCTEST_PATH), "config_patch.yaml")
-
-with open(CONFIG_PATCH_PATH) as f:
- functest_patch_yaml = yaml.safe_load(f)
+CONFIG_AARCH64_PATCH_PATH = os.path.join(os.path.dirname(
+ CONFIG_FUNCTEST_PATH), "config_aarch64_patch.yaml")
+RALLY_CONF_PATH = os.path.join("/etc/rally/rally.conf")
+RALLY_AARCH64_PATCH_PATH = os.path.join(os.path.dirname(
+ CONFIG_FUNCTEST_PATH), "rally_aarch64_patch.conf")
class PrepareEnvParser(object):
@@ -102,6 +108,38 @@ def check_env_variables():
logger.info(" IS_CI_RUN=%s" % CONST.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):
+ try:
+ installer_params = ft_utils.get_parameter_from_yaml(
+ CONST.INSTALLER_TYPE, installer_params_yaml)
+ except ValueError as e:
+ logger.debug('Printing deployment info is not supported for %s' %
+ CONST.INSTALLER_TYPE)
+ logger.debug(e)
+ else:
+ user = installer_params.get('user', None)
+ password = installer_params.get('password', None)
+ pkey = installer_params.get('pkey', None)
+ try:
+ handler = factory.Factory.get_handler(
+ installer=CONST.INSTALLER_TYPE,
+ installer_ip=CONST.INSTALLER_IP,
+ installer_user=user,
+ installer_pwd=password,
+ pkey_file=pkey)
+ if handler:
+ pod_arch = handler.get_arch()
+ except Exception as e:
+ logger.debug("Cannot get deployment information. %s" % e)
+
+
def create_directories():
print_separator()
logger.info("Creating needed directories...")
@@ -163,8 +201,7 @@ def source_rc_file():
raise Exception("The file %s is empty." % CONST.openstack_creds)
logger.info("Sourcing the OpenStack RC file...")
- os_utils.source_credentials(
- CONST.openstack_creds)
+ os_utils.source_credentials(CONST.openstack_creds)
for key, value in os.environ.iteritems():
if re.search("OS_", key):
if key == 'OS_AUTH_URL':
@@ -178,11 +215,22 @@ def source_rc_file():
def patch_config_file():
+ patch_file(CONFIG_PATCH_PATH)
+
+ if pod_arch and pod_arch in arch_filter:
+ patch_file(CONFIG_AARCH64_PATCH_PATH)
+
+
+def patch_file(patch_file_path):
+ logger.debug('Updating file: %s', patch_file_path)
+ with open(patch_file_path) as f:
+ patch_file = yaml.safe_load(f)
+
updated = False
- for key in functest_patch_yaml:
+ for key in patch_file:
if key in CONST.DEPLOY_SCENARIO:
new_functest_yaml = dict(ft_utils.merge_dicts(
- ft_utils.get_functest_yaml(), functest_patch_yaml[key]))
+ ft_utils.get_functest_yaml(), patch_file[key]))
updated = True
if updated:
@@ -210,6 +258,17 @@ def verify_deployment():
def install_rally():
print_separator()
+
+ if pod_arch and pod_arch in arch_filter:
+ logger.info("Apply aarch64 specific to rally config...")
+ with open(RALLY_AARCH64_PATCH_PATH, "r") as f:
+ rally_patch_conf = f.read()
+
+ for line in fileinput.input(RALLY_CONF_PATH, inplace=1):
+ print line,
+ if "cirros|testvm" in line:
+ print rally_patch_conf
+
logger.info("Creating Rally environment...")
cmd = "rally deployment destroy opnfv-rally"
@@ -284,34 +343,9 @@ def check_environment():
def print_deployment_info():
- 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):
- try:
- installer_params = ft_utils.get_parameter_from_yaml(
- CONST.INSTALLER_TYPE, installer_params_yaml)
- except ValueError as e:
- logger.debug('Printing deployment info is not supported for %s' %
- CONST.INSTALLER_TYPE)
- logger.debug(e)
- else:
- user = installer_params.get('user', None)
- password = installer_params.get('password', None)
- pkey = installer_params.get('pkey', None)
-
- try:
- handler = factory.Factory.get_handler(
- installer=CONST.INSTALLER_TYPE,
- installer_ip=CONST.INSTALLER_IP,
- installer_user=user,
- installer_pwd=password,
- pkey_file=pkey)
- if handler:
- logger.info('\n\nDeployment information:\n%s' %
- handler.get_deployment_info())
- except Exception as e:
- logger.debug("Cannot get deployment information. %s" % e)
+ if handler:
+ logger.info('\n\nDeployment information:\n%s' %
+ handler.get_deployment_info())
def main(**kwargs):
@@ -322,6 +356,7 @@ def main(**kwargs):
elif kwargs['action'] == "start":
logger.info("######### Preparing Functest environment #########\n")
check_env_variables()
+ get_deployment_handler()
create_directories()
source_rc_file()
patch_config_file()
diff --git a/functest/ci/rally_aarch64_patch.conf b/functest/ci/rally_aarch64_patch.conf
new file mode 100644
index 000000000..a49588bf8
--- /dev/null
+++ b/functest/ci/rally_aarch64_patch.conf
@@ -0,0 +1,5 @@
+img_name_regex = ^TestVM$
+img_url = http://download.cirros-cloud.net/daily/20161201/cirros-d161201-aarch64-disk.img
+flavor_ref_ram = 128
+flavor_ref_alt_ram = 256
+heat_instance_type_ram = 128
diff --git a/functest/ci/testcases.yaml b/functest/ci/testcases.yaml
index 1e5ba758c..77cd1ae64 100755
--- a/functest/ci/testcases.yaml
+++ b/functest/ci/testcases.yaml
@@ -74,7 +74,7 @@ tiers:
over a private network.
dependencies:
installer: ''
- scenario: '^((?!bgpvpn|odl_l3).)*$'
+ scenario: '^((?!odl_l3).)*$'
run:
module: 'functest.opnfv_tests.openstack.vping.vping_ssh'
class: 'VPingSSH'
@@ -118,7 +118,7 @@ tiers:
Rally suite in smoke mode.
dependencies:
installer: ''
- scenario: '^((?!bgpvpn).)*$'
+ scenario: ''
run:
module: 'functest.opnfv_tests.openstack.rally.rally'
class: 'RallySanity'
@@ -318,6 +318,18 @@ tiers:
module: 'functest.opnfv_tests.vnf.rnc.parser'
class: 'Parser'
-
+ name: domino
+ criteria: 'status == "PASS"'
+ blocking: false
+ description: >-
+ Test suite from Domino project.
+ dependencies:
+ installer: ''
+ scenario: ''
+ run:
+ module: 'functest.opnfv_tests.features.domino'
+ class: 'Domino'
+ -
name: orchestra
criteria: 'ret == 0'
blocking: false
@@ -390,6 +402,22 @@ tiers:
run:
module: 'functest.opnfv_tests.openstack.tempest.tempest'
class: 'TempestDefcore'
+ -
+ name: tempest_custom
+ criteria: 'success_rate == 100%'
+ blocking: false
+ description: >-
+ The test case allows running a customized list of tempest
+ test cases defined in a file under
+ <dir_functest_repo>/functest/opnfv_tests/openstack/
+ /tempest/custom_tests/test_list.txt
+ The file is empty and can be customized with the desired tests.
+ dependencies:
+ installer: 'unknown'
+ scenario: 'unknown'
+ run:
+ module: 'functest.opnfv_tests.openstack.tempest.tempest'
+ class: 'TempestCustom'
# -
# name: rally_full
# criteria: 'success_rate >= 90%'
@@ -475,3 +503,16 @@ tiers:
run:
module: 'functest.opnfv_tests.vnf.ims.opera_ims'
class: 'ImsVnf'
+
+ -
+ name: vyos_vrouter
+ criteria: 'status == "PASS"'
+ blocking: false
+ description: >-
+ This test case is vRouter testing.
+ dependencies:
+ installer: 'fuel'
+ scenario: 'nosdn-nofeature'
+ run:
+ module: 'functest.opnfv_tests.vnf.router.vyos_vrouter'
+ class: 'VrouterVnf'
diff --git a/functest/opnfv_tests/openstack/rally/scenario/templates/server_with_ports.yaml.template b/functest/opnfv_tests/openstack/rally/scenario/templates/server_with_ports.yaml.template
index 909f45d21..ed5e61fe0 100644
--- a/functest/opnfv_tests/openstack/rally/scenario/templates/server_with_ports.yaml.template
+++ b/functest/opnfv_tests/openstack/rally/scenario/templates/server_with_ports.yaml.template
@@ -7,7 +7,7 @@ parameters:
default: public
image:
type: string
- default: cirros-0.3.4-x86_64-uec
+ default: cirros-0.3.5-x86_64-uec
flavor:
type: string
default: m1.tiny
diff --git a/functest/opnfv_tests/openstack/rally/scenario/templates/server_with_volume.yaml.template b/functest/opnfv_tests/openstack/rally/scenario/templates/server_with_volume.yaml.template
index 826ca9dae..116b5bb6c 100644
--- a/functest/opnfv_tests/openstack/rally/scenario/templates/server_with_volume.yaml.template
+++ b/functest/opnfv_tests/openstack/rally/scenario/templates/server_with_volume.yaml.template
@@ -4,7 +4,7 @@ parameters:
# set all correct defaults for parameters before launch test
image:
type: string
- default: cirros-0.3.4-x86_64-uec
+ default: cirros-0.3.5-x86_64-uec
flavor:
type: string
default: m1.tiny
diff --git a/functest/opnfv_tests/openstack/tempest/custom_tests/blacklist.txt b/functest/opnfv_tests/openstack/tempest/custom_tests/blacklist.txt
index 0a4256ce6..fcdfe225b 100644
--- a/functest/opnfv_tests/openstack/tempest/custom_tests/blacklist.txt
+++ b/functest/opnfv_tests/openstack/tempest/custom_tests/blacklist.txt
@@ -1,22 +1,3 @@
--
- scenarios:
- - os-odl_l2-bgpvpn-ha
- - os-odl_l2-bgpvpn-noha
- installers:
- - fuel
- - apex
- tests:
- - tempest.api.compute.servers.test_create_server.ServersTestJSON.test_list_servers
- - tempest.api.compute.servers.test_create_server.ServersTestJSON.test_verify_server_details
- - tempest.api.compute.servers.test_create_server.ServersTestManualDisk.test_list_servers
- - tempest.api.compute.servers.test_create_server.ServersTestManualDisk.test_verify_server_details
- - tempest.api.compute.servers.test_server_actions.ServerActionsTestJSON.test_reboot_server_hard
- - tempest.api.network.test_floating_ips.FloatingIPTestJSON.test_create_list_show_update_delete_floating_ip
- - tempest.api.network.test_floating_ips.FloatingIPTestJSON.test_create_floating_ip_specifying_a_fixed_ip_address
- - tempest.scenario.test_network_basic_ops.TestNetworkBasicOps.test_network_basic_ops
- - tempest.scenario.test_server_basic_ops.TestServerBasicOps.test_server_basic_ops
- - tempest.scenario.test_volume_boot_pattern.TestVolumeBootPattern.test_volume_boot_pattern
- - tempest.scenario.test_volume_boot_pattern.TestVolumeBootPatternV2.test_volume_boot_pattern
-
scenarios:
diff --git a/functest/opnfv_tests/openstack/tempest/custom_tests/test_list.txt b/functest/opnfv_tests/openstack/tempest/custom_tests/test_list.txt
new file mode 100644
index 000000000..ac4e37289
--- /dev/null
+++ b/functest/opnfv_tests/openstack/tempest/custom_tests/test_list.txt
@@ -0,0 +1,4 @@
+# This is an empty file to be filled up with the desired tempest test cases
+# Examples:
+#tempest.scenario.test_server_basic_ops.TestServerBasicOps.test_server_basic_ops
+#tempest.scenario.test_network_basic_ops.TestNetworkBasicOps.test_network_basic_ops \ No newline at end of file
diff --git a/functest/opnfv_tests/openstack/tempest/tempest.py b/functest/opnfv_tests/openstack/tempest/tempest.py
index 37b5c0ee7..4c96500db 100644
--- a/functest/opnfv_tests/openstack/tempest/tempest.py
+++ b/functest/opnfv_tests/openstack/tempest/tempest.py
@@ -324,11 +324,11 @@ class TempestMultisite(TempestCommon):
class TempestCustom(TempestCommon):
- def __init__(self, mode, option):
+ def __init__(self):
TempestCommon.__init__(self)
self.case_name = "tempest_custom"
- self.MODE = mode
- self.OPTION = option
+ self.MODE = "custom"
+ self.OPTION = "--concurrency 1"
class TempestDefcore(TempestCommon):
diff --git a/functest/opnfv_tests/vnf/ims/cloudify_ims.py b/functest/opnfv_tests/vnf/ims/cloudify_ims.py
index 584d780a5..c2c251ad2 100644
--- a/functest/opnfv_tests/vnf/ims/cloudify_ims.py
+++ b/functest/opnfv_tests/vnf/ims/cloudify_ims.py
@@ -195,8 +195,9 @@ class ImsVnf(vnf_base.VnfOnBoardingBase):
return {'status': 'PASS', 'result': ''}
def deploy_vnf(self):
- cw = Clearwater(self.vnf.inputs, self.orchestrator.object, self.logger)
- self.vnf.object = cw
+ cw = Clearwater(self.vnf['inputs'], self.orchestrator['object'],
+ self.logger)
+ self.vnf['object'] = cw
self.logger.info("Collect flavor id for all clearwater vm")
flavor_exist, flavor_id = os_utils.get_or_create_flavor(
@@ -215,7 +216,7 @@ class ImsVnf(vnf_base.VnfOnBoardingBase):
cw.set_flavor_id(flavor_id)
# VMs image
- if 'os_image' in self.vnf.requirements.keys():
+ if 'os_image' in self.vnf['requirements'].keys():
image_id = os_utils.get_image_id(
self.glance_client, self.vnf['requirements']['os_image'])
if image_id == '':
@@ -256,7 +257,7 @@ class ImsVnf(vnf_base.VnfOnBoardingBase):
api_url = "http://" + mgr_ip + "/api/v2"
dep_outputs = requests.get(api_url + "/deployments/" +
- self.vnf.deployment_name + "/outputs")
+ self.vnf['deployment_name'] + "/outputs")
dns_ip = dep_outputs.json()['outputs']['dns_ip']
ellis_ip = dep_outputs.json()['outputs']['ellis_ip']
@@ -340,8 +341,8 @@ class ImsVnf(vnf_base.VnfOnBoardingBase):
return {'status': 'FAIL', 'result': ''}
def clean(self):
- self.vnf.object.undeploy_vnf()
- self.orchestrator.object.undeploy_manager()
+ self.vnf['object'].undeploy_vnf()
+ self.orchestrator['object'].undeploy_manager()
super(ImsVnf, self).clean()
def main(self, **kwargs):
diff --git a/functest/opnfv_tests/vnf/router/__init__.py b/functest/opnfv_tests/vnf/router/__init__.py
new file mode 100755
index 000000000..e69de29bb
--- /dev/null
+++ 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
new file mode 100755
index 000000000..94a3ecfd8
--- /dev/null
+++ b/functest/opnfv_tests/vnf/router/vyos_vrouter.py
@@ -0,0 +1,33 @@
+#!/usr/bin/env python
+#
+# Copyright 2017 Okinawa Open Laboratory
+#
+# 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 functest.core.feature_base as base
+import json
+import os
+
+RESULT_DETAILS_FILE = "test_result.json"
+
+
+class VrouterVnf(base.FeatureBase):
+ def __init__(self):
+ super(VrouterVnf, self).__init__(project='vRouter',
+ case='vyos_vrouter',
+ repo='dir_repo_vrouter')
+ self.cmd = 'cd %s && ./run.sh' % self.repo
+
+ def set_result_details(self):
+ filepath = os.path.join(self.repo, RESULT_DETAILS_FILE)
+ if os.path.exists(filepath):
+ f = open(filepath, 'r')
+ self.details = json.load(f)
+ f.close()
+
+ def log_results(self):
+ if self.criteria == 'PASS':
+ self.set_result_details()
+ super(VrouterVnf, self).log_results()
diff --git a/functest/tests/unit/opnfv_tests/vnf/__init__.py b/functest/tests/unit/opnfv_tests/vnf/__init__.py
new file mode 100644
index 000000000..e69de29bb
--- /dev/null
+++ b/functest/tests/unit/opnfv_tests/vnf/__init__.py
diff --git a/functest/tests/unit/opnfv_tests/vnf/ims/__init__.py b/functest/tests/unit/opnfv_tests/vnf/ims/__init__.py
new file mode 100644
index 000000000..e69de29bb
--- /dev/null
+++ b/functest/tests/unit/opnfv_tests/vnf/ims/__init__.py
diff --git a/functest/tests/unit/opnfv_tests/vnf/ims/test_clearwater.py b/functest/tests/unit/opnfv_tests/vnf/ims/test_clearwater.py
new file mode 100644
index 000000000..527f12e59
--- /dev/null
+++ b/functest/tests/unit/opnfv_tests/vnf/ims/test_clearwater.py
@@ -0,0 +1,54 @@
+#!/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.opnfv_tests.vnf.ims import clearwater
+from functest.opnfv_tests.vnf.ims import orchestrator_cloudify
+
+
+class ClearwaterTesting(unittest.TestCase):
+
+ logging.disable(logging.CRITICAL)
+
+ def setUp(self):
+ self.clearwater = clearwater.Clearwater()
+ self.orchestrator = orchestrator_cloudify.Orchestrator('test_dir')
+ self.clearwater.orchestrator = self.orchestrator
+ self.clearwater.dep_name = 'test_dep_name'
+ self.bp = {'file_name': 'test_file',
+ 'destination_folder': 'test_folder',
+ 'url': 'test_url',
+ 'branch': 'test_branch'}
+
+ def test_deploy_vnf_blueprint_download_failed(self):
+ with mock.patch.object(self.clearwater.orchestrator,
+ 'download_upload_and_deploy_blueprint',
+ return_value='error'):
+ self.assertEqual(self.clearwater.deploy_vnf(self.bp),
+ 'error')
+
+ def test_deploy_vnf_blueprint_download_passed(self):
+ with mock.patch.object(self.clearwater.orchestrator,
+ 'download_upload_and_deploy_blueprint',
+ return_value=''):
+ self.clearwater.deploy_vnf(self.bp),
+ self.assertEqual(self.clearwater.deploy, True)
+
+ def test_undeploy_vnf_deployment_passed(self):
+ with mock.patch.object(self.clearwater.orchestrator,
+ 'undeploy_deployment'):
+ self.clearwater.deploy = True
+ self.clearwater.undeploy_vnf(),
+ self.assertEqual(self.clearwater.deploy, False)
+
+
+if __name__ == "__main__":
+ unittest.main(verbosity=2)
diff --git a/functest/tests/unit/opnfv_tests/vnf/ims/test_cloudify_ims.py b/functest/tests/unit/opnfv_tests/vnf/ims/test_cloudify_ims.py
new file mode 100644
index 000000000..e25816f01
--- /dev/null
+++ b/functest/tests/unit/opnfv_tests/vnf/ims/test_cloudify_ims.py
@@ -0,0 +1,542 @@
+#!/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.opnfv_tests.vnf.ims import cloudify_ims
+
+
+class ImsVnfTesting(unittest.TestCase):
+
+ logging.disable(logging.CRITICAL)
+
+ def setUp(self):
+ with mock.patch('functest.opnfv_tests.vnf.ims.cloudify_ims.'
+ 'os.makedirs'), \
+ mock.patch('functest.opnfv_tests.vnf.ims.cloudify_ims.'
+ 'get_config', return_value='config_value'):
+ self.ims_vnf = cloudify_ims.ImsVnf()
+ self.neutron_client = mock.Mock()
+ self.glance_client = mock.Mock()
+ self.keystone_client = mock.Mock()
+ self.nova_client = mock.Mock()
+ self.orchestrator = {'requirements': {'ram_min': 2,
+ 'os_image': 'test_os_image'},
+ 'blueprint': {'url': 'test_url',
+ 'branch': 'test_branch'},
+ 'inputs': {'public_domain': 'test_domain'},
+ 'object': 'test_object',
+ 'deployment_name': 'test_deployment_name'}
+ self.ims_vnf.orchestrator = self.orchestrator
+ self.ims_vnf.images = {'test_image': 'test_url'}
+ self.ims_vnf.vnf = self.orchestrator
+ self.ims_vnf.tenant_name = 'test_tenant'
+ self.ims_vnf.inputs = {'public_domain': 'test_domain'}
+ self.ims_vnf.glance_client = self.glance_client
+ self.ims_vnf.neutron_client = self.neutron_client
+ self.ims_vnf.keystone_client = self.keystone_client
+ self.ims_vnf.nova_client = self.nova_client
+ self.ims_vnf.admin_creds = 'test_creds'
+
+ self.mock_post = mock.Mock()
+ attrs = {'status_code': 201,
+ 'cookies': ""}
+ self.mock_post.configure_mock(**attrs)
+
+ self.mock_post_200 = mock.Mock()
+ attrs = {'status_code': 200,
+ 'cookies': ""}
+ self.mock_post_200.configure_mock(**attrs)
+
+ def test_deploy_orchestrator_missing_image(self):
+ with mock.patch('functest.opnfv_tests.vnf.ims.cloudify_ims.'
+ 'os_utils.get_neutron_client',
+ return_value=self.neutron_client), \
+ mock.patch('functest.opnfv_tests.vnf.ims.cloudify_ims.'
+ 'os_utils.get_glance_client',
+ return_value=self.glance_client), \
+ mock.patch('functest.opnfv_tests.vnf.ims.cloudify_ims.'
+ 'os_utils.get_keystone_client',
+ return_value=self.keystone_client), \
+ mock.patch('functest.opnfv_tests.vnf.ims.cloudify_ims.'
+ 'os_utils.get_nova_client',
+ return_value=self.nova_client), \
+ mock.patch('functest.opnfv_tests.vnf.ims.cloudify_ims.'
+ 'os_utils.get_image_id',
+ return_value=''), \
+ mock.patch('functest.opnfv_tests.vnf.ims.cloudify_ims.'
+ 'download_and_add_image_on_glance') as m, \
+ self.assertRaises(Exception) as context:
+ self.ims_vnf.deploy_orchestrator()
+ self.assertTrue(m.called)
+ msg = "Failed to find or upload required OS "
+ msg += "image for this deployment"
+ self.assertTrue(msg in context.exception)
+
+ def test_deploy_orchestrator_extend_quota_fail(self):
+ with mock.patch('functest.opnfv_tests.vnf.ims.cloudify_ims.'
+ 'os_utils.get_neutron_client',
+ return_value=self.neutron_client), \
+ mock.patch('functest.opnfv_tests.vnf.ims.cloudify_ims.'
+ 'os_utils.get_glance_client',
+ return_value=self.glance_client), \
+ mock.patch('functest.opnfv_tests.vnf.ims.cloudify_ims.'
+ 'os_utils.get_keystone_client',
+ return_value=self.keystone_client), \
+ mock.patch('functest.opnfv_tests.vnf.ims.cloudify_ims.'
+ 'os_utils.get_nova_client',
+ return_value=self.nova_client), \
+ mock.patch('functest.opnfv_tests.vnf.ims.cloudify_ims.'
+ 'os_utils.get_image_id',
+ return_value='image_id'), \
+ mock.patch('functest.opnfv_tests.vnf.ims.cloudify_ims.'
+ 'os_utils.get_tenant_id',
+ return_value='tenant_id'), \
+ mock.patch('functest.opnfv_tests.vnf.ims.cloudify_ims.'
+ 'os_utils.update_sg_quota',
+ return_value=False), \
+ self.assertRaises(Exception) as context:
+ self.ims_vnf.deploy_orchestrator()
+ msg = "Failed to update security group quota"
+ msg += " for tenant test_tenant"
+ self.assertTrue(msg in context.exception)
+
+ def _get_image_id(self, client, name):
+ if name == 'test_image':
+ return 'image_id'
+ else:
+ return ''
+
+ def test_deploy_orchestrator_missing_flavor(self):
+ with mock.patch('functest.opnfv_tests.vnf.ims.cloudify_ims.'
+ 'os_utils.get_neutron_client',
+ return_value=self.neutron_client), \
+ mock.patch('functest.opnfv_tests.vnf.ims.cloudify_ims.'
+ 'os_utils.get_glance_client',
+ return_value=self.glance_client), \
+ mock.patch('functest.opnfv_tests.vnf.ims.cloudify_ims.'
+ 'os_utils.get_keystone_client',
+ return_value=self.keystone_client), \
+ mock.patch('functest.opnfv_tests.vnf.ims.cloudify_ims.'
+ 'os_utils.get_nova_client',
+ return_value=self.nova_client), \
+ mock.patch('functest.opnfv_tests.vnf.ims.cloudify_ims.'
+ 'os_utils.get_image_id',
+ side_effect=self._get_image_id), \
+ mock.patch('functest.opnfv_tests.vnf.ims.cloudify_ims.'
+ 'os_utils.get_tenant_id',
+ return_value='tenant_id'), \
+ mock.patch('functest.opnfv_tests.vnf.ims.cloudify_ims.'
+ 'os_utils.update_sg_quota',
+ return_value=True), \
+ mock.patch('functest.opnfv_tests.vnf.ims.cloudify_ims.'
+ 'os_utils.get_endpoint',
+ return_value='public_auth_url'), \
+ mock.patch('functest.opnfv_tests.vnf.ims.cloudify_ims.'
+ 'Orchestrator', return_value=mock.Mock()) as m, \
+ mock.patch('functest.opnfv_tests.vnf.ims.cloudify_ims.'
+ 'os_utils.get_or_create_flavor',
+ return_value=(False, '')), \
+ self.assertRaises(Exception) as context:
+ self.ims_vnf.deploy_orchestrator()
+ self.assertTrue(m.set_credentials.called)
+ msg = "Failed to find required flavorfor this deployment"
+ self.assertTrue(msg in context.exception)
+
+ def test_deploy_orchestrator_missing_os_image(self):
+ with mock.patch('functest.opnfv_tests.vnf.ims.cloudify_ims.'
+ 'os_utils.get_neutron_client',
+ return_value=self.neutron_client), \
+ mock.patch('functest.opnfv_tests.vnf.ims.cloudify_ims.'
+ 'os_utils.get_glance_client',
+ return_value=self.glance_client), \
+ mock.patch('functest.opnfv_tests.vnf.ims.cloudify_ims.'
+ 'os_utils.get_keystone_client',
+ return_value=self.keystone_client), \
+ mock.patch('functest.opnfv_tests.vnf.ims.cloudify_ims.'
+ 'os_utils.get_nova_client',
+ return_value=self.nova_client), \
+ mock.patch('functest.opnfv_tests.vnf.ims.cloudify_ims.'
+ 'os_utils.get_image_id',
+ side_effect=self._get_image_id), \
+ mock.patch('functest.opnfv_tests.vnf.ims.cloudify_ims.'
+ 'os_utils.get_tenant_id',
+ return_value='tenant_id'), \
+ mock.patch('functest.opnfv_tests.vnf.ims.cloudify_ims.'
+ 'os_utils.update_sg_quota',
+ return_value=True), \
+ mock.patch('functest.opnfv_tests.vnf.ims.cloudify_ims.'
+ 'os_utils.get_endpoint',
+ return_value='public_auth_url'), \
+ mock.patch('functest.opnfv_tests.vnf.ims.cloudify_ims.'
+ 'Orchestrator', return_value=mock.Mock()) as m, \
+ mock.patch('functest.opnfv_tests.vnf.ims.cloudify_ims.'
+ 'os_utils.get_or_create_flavor',
+ return_value=(True, 'flavor_id')), \
+ self.assertRaises(Exception) as context:
+ self.ims_vnf.deploy_orchestrator()
+ self.assertTrue(m.set_credentials.called)
+ self.assertTrue(m.set_flavor_id.called)
+ msg = "Failed to find required OS image for cloudify manager"
+ self.assertTrue(msg in context.exception)
+
+ def test_deploy_orchestrator_get_ext_network_fail(self):
+ with mock.patch('functest.opnfv_tests.vnf.ims.cloudify_ims.'
+ 'os_utils.get_neutron_client',
+ return_value=self.neutron_client), \
+ mock.patch('functest.opnfv_tests.vnf.ims.cloudify_ims.'
+ 'os_utils.get_glance_client',
+ return_value=self.glance_client), \
+ mock.patch('functest.opnfv_tests.vnf.ims.cloudify_ims.'
+ 'os_utils.get_keystone_client',
+ return_value=self.keystone_client), \
+ mock.patch('functest.opnfv_tests.vnf.ims.cloudify_ims.'
+ 'os_utils.get_nova_client',
+ return_value=self.nova_client), \
+ mock.patch('functest.opnfv_tests.vnf.ims.cloudify_ims.'
+ 'os_utils.get_image_id',
+ return_value='image_id'), \
+ mock.patch('functest.opnfv_tests.vnf.ims.cloudify_ims.'
+ 'os_utils.get_tenant_id',
+ return_value='tenant_id'), \
+ mock.patch('functest.opnfv_tests.vnf.ims.cloudify_ims.'
+ 'os_utils.update_sg_quota',
+ return_value=True), \
+ mock.patch('functest.opnfv_tests.vnf.ims.cloudify_ims.'
+ 'os_utils.get_endpoint',
+ return_value='public_auth_url'), \
+ mock.patch('functest.opnfv_tests.vnf.ims.cloudify_ims.'
+ 'Orchestrator', return_value=mock.Mock()) as m, \
+ mock.patch('functest.opnfv_tests.vnf.ims.cloudify_ims.'
+ 'os_utils.get_or_create_flavor',
+ return_value=(True, 'flavor_id')), \
+ mock.patch('functest.opnfv_tests.vnf.ims.cloudify_ims.'
+ 'os_utils.get_external_net',
+ return_value=''), \
+ self.assertRaises(Exception) as context:
+ self.ims_vnf.deploy_orchestrator()
+ self.assertTrue(m.set_credentials.called)
+ self.assertTrue(m.set_flavor_id.called)
+ self.assertTrue(m.set_image_id.called)
+ msg = "Failed to get external network"
+ self.assertTrue(msg in context.exception)
+
+ def test_deploy_orchestrator_with_error(self):
+ with mock.patch('functest.opnfv_tests.vnf.ims.cloudify_ims.'
+ 'os_utils.get_neutron_client',
+ return_value=self.neutron_client), \
+ mock.patch('functest.opnfv_tests.vnf.ims.cloudify_ims.'
+ 'os_utils.get_glance_client',
+ return_value=self.glance_client), \
+ mock.patch('functest.opnfv_tests.vnf.ims.cloudify_ims.'
+ 'os_utils.get_keystone_client',
+ return_value=self.keystone_client), \
+ mock.patch('functest.opnfv_tests.vnf.ims.cloudify_ims.'
+ 'os_utils.get_nova_client',
+ return_value=self.nova_client), \
+ mock.patch('functest.opnfv_tests.vnf.ims.cloudify_ims.'
+ 'os_utils.get_image_id',
+ return_value='image_id'), \
+ mock.patch('functest.opnfv_tests.vnf.ims.cloudify_ims.'
+ 'os_utils.get_tenant_id',
+ return_value='tenant_id'), \
+ mock.patch('functest.opnfv_tests.vnf.ims.cloudify_ims.'
+ 'os_utils.update_sg_quota',
+ return_value=True), \
+ mock.patch('functest.opnfv_tests.vnf.ims.cloudify_ims.'
+ 'os_utils.get_endpoint',
+ return_value='public_auth_url'), \
+ mock.patch('functest.opnfv_tests.vnf.ims.cloudify_ims.'
+ 'Orchestrator') as m, \
+ mock.patch('functest.opnfv_tests.vnf.ims.cloudify_ims.'
+ 'os_utils.get_or_create_flavor',
+ return_value=(True, 'flavor_id')), \
+ mock.patch('functest.opnfv_tests.vnf.ims.cloudify_ims.'
+ 'os_utils.get_external_net',
+ return_value='ext_net'), \
+ mock.patch('functest.opnfv_tests.vnf.ims.cloudify_ims.'
+ 'ft_utils.get_resolvconf_ns',
+ return_value=True), \
+ mock.patch('functest.opnfv_tests.vnf.ims.cloudify_ims.'
+ 'ft_utils.execute_command'):
+ mock_obj = mock.Mock()
+ attrs = {'deploy_manager.return_value': 'error'}
+ mock_obj.configure_mock(**attrs)
+
+ m.return_value = mock_obj
+
+ self.assertEqual(self.ims_vnf.deploy_orchestrator(),
+ {'status': 'FAIL', 'result': 'error'})
+
+ def test_deploy_orchestrator_default(self):
+ with mock.patch('functest.opnfv_tests.vnf.ims.cloudify_ims.'
+ 'os_utils.get_neutron_client',
+ return_value=self.neutron_client), \
+ mock.patch('functest.opnfv_tests.vnf.ims.cloudify_ims.'
+ 'os_utils.get_glance_client',
+ return_value=self.glance_client), \
+ mock.patch('functest.opnfv_tests.vnf.ims.cloudify_ims.'
+ 'os_utils.get_keystone_client',
+ return_value=self.keystone_client), \
+ mock.patch('functest.opnfv_tests.vnf.ims.cloudify_ims.'
+ 'os_utils.get_nova_client',
+ return_value=self.nova_client), \
+ mock.patch('functest.opnfv_tests.vnf.ims.cloudify_ims.'
+ 'os_utils.get_image_id',
+ return_value='image_id'), \
+ mock.patch('functest.opnfv_tests.vnf.ims.cloudify_ims.'
+ 'os_utils.get_tenant_id',
+ return_value='tenant_id'), \
+ mock.patch('functest.opnfv_tests.vnf.ims.cloudify_ims.'
+ 'os_utils.update_sg_quota',
+ return_value=True), \
+ mock.patch('functest.opnfv_tests.vnf.ims.cloudify_ims.'
+ 'os_utils.get_endpoint',
+ return_value='public_auth_url'), \
+ mock.patch('functest.opnfv_tests.vnf.ims.cloudify_ims.'
+ 'Orchestrator') as m, \
+ mock.patch('functest.opnfv_tests.vnf.ims.cloudify_ims.'
+ 'os_utils.get_or_create_flavor',
+ return_value=(True, 'flavor_id')), \
+ mock.patch('functest.opnfv_tests.vnf.ims.cloudify_ims.'
+ 'os_utils.get_external_net',
+ return_value='ext_net'), \
+ mock.patch('functest.opnfv_tests.vnf.ims.cloudify_ims.'
+ 'ft_utils.get_resolvconf_ns',
+ return_value=True), \
+ mock.patch('functest.opnfv_tests.vnf.ims.cloudify_ims.'
+ 'ft_utils.execute_command'):
+ mock_obj = mock.Mock()
+ attrs = {'deploy_manager.return_value': ''}
+ mock_obj.configure_mock(**attrs)
+
+ m.return_value = mock_obj
+
+ self.assertEqual(self.ims_vnf.deploy_orchestrator(),
+ {'status': 'PASS', 'result': ''})
+
+ def test_deploy_vnf_missing_flavor(self):
+ with mock.patch('functest.opnfv_tests.vnf.ims.cloudify_ims.'
+ 'Clearwater', return_value=mock.Mock()), \
+ mock.patch('functest.opnfv_tests.vnf.ims.cloudify_ims.'
+ 'os_utils.get_or_create_flavor',
+ return_value=(False, '')), \
+ self.assertRaises(Exception) as context:
+ self.ims_vnf.deploy_vnf()
+ msg = "Failed to find required flavor for this deployment"
+ self.assertTrue(msg in context.exception)
+
+ def test_deploy_vnf_missing_os_image(self):
+ with mock.patch('functest.opnfv_tests.vnf.ims.cloudify_ims.'
+ 'Clearwater', return_value=mock.Mock()) as m, \
+ mock.patch('functest.opnfv_tests.vnf.ims.cloudify_ims.'
+ 'os_utils.get_or_create_flavor',
+ return_value=(True, 'test_flavor')), \
+ mock.patch('functest.opnfv_tests.vnf.ims.cloudify_ims.'
+ 'os_utils.get_image_id',
+ return_value=''), \
+ self.assertRaises(Exception) as context:
+ self.ims_vnf.deploy_vnf()
+ msg = "Failed to find required OS image"
+ msg += " for clearwater VMs"
+ self.assertTrue(msg in context.exception)
+ self.assertTrue(m.set_flavor_id.called)
+
+ def test_deploy_vnf_missing_get_ext_net(self):
+ with mock.patch('functest.opnfv_tests.vnf.ims.cloudify_ims.'
+ 'Clearwater', return_value=mock.Mock()) as m, \
+ mock.patch('functest.opnfv_tests.vnf.ims.cloudify_ims.'
+ 'os_utils.get_or_create_flavor',
+ return_value=(True, 'test_flavor')), \
+ mock.patch('functest.opnfv_tests.vnf.ims.cloudify_ims.'
+ 'os_utils.get_image_id',
+ return_value='image_id'), \
+ mock.patch('functest.opnfv_tests.vnf.ims.cloudify_ims.'
+ 'os_utils.get_external_net',
+ return_value=''), \
+ self.assertRaises(Exception) as context:
+ self.ims_vnf.deploy_vnf()
+ msg = "Failed to get external network"
+ self.assertTrue(msg in context.exception)
+ self.assertTrue(m.set_flavor_id.called)
+ self.assertTrue(m.set_image_id.called)
+
+ def test_deploy_vnf_with_error(self):
+ with mock.patch('functest.opnfv_tests.vnf.ims.cloudify_ims.'
+ 'Clearwater') as m, \
+ mock.patch('functest.opnfv_tests.vnf.ims.cloudify_ims.'
+ 'os_utils.get_or_create_flavor',
+ return_value=(True, 'test_flavor')), \
+ mock.patch('functest.opnfv_tests.vnf.ims.cloudify_ims.'
+ 'os_utils.get_image_id',
+ return_value='image_id'), \
+ mock.patch('functest.opnfv_tests.vnf.ims.cloudify_ims.'
+ 'os_utils.get_external_net',
+ return_value='ext_net'):
+ mock_obj = mock.Mock()
+ attrs = {'deploy_vnf.return_value': 'error'}
+ mock_obj.configure_mock(**attrs)
+
+ m.return_value = mock_obj
+
+ self.assertEqual(self.ims_vnf.deploy_vnf(),
+ {'status': 'FAIL', 'result': 'error'})
+
+ def test_deploy_vnf_default(self):
+ with mock.patch('functest.opnfv_tests.vnf.ims.cloudify_ims.'
+ 'Clearwater') as m, \
+ mock.patch('functest.opnfv_tests.vnf.ims.cloudify_ims.'
+ 'os_utils.get_or_create_flavor',
+ return_value=(True, 'test_flavor')), \
+ mock.patch('functest.opnfv_tests.vnf.ims.cloudify_ims.'
+ 'os_utils.get_image_id',
+ return_value='image_id'), \
+ mock.patch('functest.opnfv_tests.vnf.ims.cloudify_ims.'
+ 'os_utils.get_external_net',
+ return_value='ext_net'):
+ mock_obj = mock.Mock()
+ attrs = {'deploy_vnf.return_value': ''}
+ mock_obj.configure_mock(**attrs)
+
+ m.return_value = mock_obj
+
+ self.assertEqual(self.ims_vnf.deploy_vnf(),
+ {'status': 'PASS', 'result': ''})
+
+ def test_test_vnf_ip_retrieval_failure(self):
+ with mock.patch('functest.opnfv_tests.vnf.ims.cloudify_ims.'
+ 'os.popen', side_effect=Exception), \
+ self.assertRaises(Exception) as context:
+ msg = "Unable to retrieve the IP of the "
+ msg += "cloudify manager server !"
+ self.ims_vnf.test_vnf()
+ self.assertTrue(msg in context.exception)
+
+ def test_test_vnf_create_number_failure(self):
+ with mock.patch('functest.opnfv_tests.vnf.ims.cloudify_ims.'
+ 'os.popen') as m, \
+ mock.patch('functest.opnfv_tests.vnf.ims.cloudify_ims.'
+ 'requests.get'), \
+ mock.patch('functest.opnfv_tests.vnf.ims.cloudify_ims.'
+ 'requests.post',
+ return_value=self.mock_post), \
+ self.assertRaises(Exception) as context:
+ mock_obj = mock.Mock()
+ attrs = {'read.return_value': 'test_ip\n'}
+ mock_obj.configure_mock(**attrs)
+ m.return_value = mock_obj
+
+ self.ims_vnf.test_vnf()
+
+ msg = "Unable to create a number:"
+ self.assertTrue(msg in context.exception)
+
+ def _get_post_status(self, url, cookies='', data=''):
+ ellis_url = "http://test_ellis_ip/session"
+ if url == ellis_url:
+ return self.mock_post_200
+ return self.mock_post
+
+ def test_test_vnf_fail(self):
+ with mock.patch('functest.opnfv_tests.vnf.ims.cloudify_ims.'
+ 'os.popen') as m, \
+ mock.patch('functest.opnfv_tests.vnf.ims.cloudify_ims.'
+ 'requests.get') as mock_get, \
+ mock.patch('functest.opnfv_tests.vnf.ims.cloudify_ims.'
+ 'requests.post',
+ side_effect=self._get_post_status), \
+ mock.patch('functest.opnfv_tests.vnf.ims.cloudify_ims.'
+ 'ft_utils.get_resolvconf_ns'), \
+ mock.patch('__builtin__.open', mock.mock_open()), \
+ mock.patch('functest.opnfv_tests.vnf.ims.cloudify_ims.'
+ 'subprocess.call'), \
+ mock.patch('functest.opnfv_tests.vnf.ims.cloudify_ims.'
+ 'os.remove'), \
+ mock.patch('functest.opnfv_tests.vnf.ims.cloudify_ims.'
+ 'json.load', return_value=''):
+ mock_obj = mock.Mock()
+ attrs = {'read.return_value': 'test_ip\n'}
+ mock_obj.configure_mock(**attrs)
+ m.return_value = mock_obj
+
+ mock_obj2 = mock.Mock()
+ attrs = {'json.return_value': {'outputs':
+ {'dns_ip': 'test_dns_ip',
+ 'ellis_ip': 'test_ellis_ip'}}}
+ mock_obj2.configure_mock(**attrs)
+ mock_get.return_value = mock_obj2
+
+ self.assertEqual(self.ims_vnf.test_vnf(),
+ {'status': 'FAIL', 'result': ''})
+
+ def test_test_vnf_pass(self):
+ with mock.patch('functest.opnfv_tests.vnf.ims.cloudify_ims.'
+ 'os.popen') as m, \
+ mock.patch('functest.opnfv_tests.vnf.ims.cloudify_ims.'
+ 'requests.get') as mock_get, \
+ mock.patch('functest.opnfv_tests.vnf.ims.cloudify_ims.'
+ 'requests.post',
+ side_effect=self._get_post_status), \
+ mock.patch('functest.opnfv_tests.vnf.ims.cloudify_ims.'
+ 'ft_utils.get_resolvconf_ns'), \
+ mock.patch('__builtin__.open', mock.mock_open()), \
+ mock.patch('functest.opnfv_tests.vnf.ims.cloudify_ims.'
+ 'subprocess.call'), \
+ mock.patch('functest.opnfv_tests.vnf.ims.cloudify_ims.'
+ 'os.remove'), \
+ mock.patch('functest.opnfv_tests.vnf.ims.cloudify_ims.'
+ 'json.load', return_value='vims_test_result'):
+ mock_obj = mock.Mock()
+ attrs = {'read.return_value': 'test_ip\n'}
+ mock_obj.configure_mock(**attrs)
+ m.return_value = mock_obj
+
+ mock_obj2 = mock.Mock()
+ attrs = {'json.return_value': {'outputs':
+ {'dns_ip': 'test_dns_ip',
+ 'ellis_ip': 'test_ellis_ip'}}}
+ mock_obj2.configure_mock(**attrs)
+ mock_get.return_value = mock_obj2
+
+ self.assertEqual(self.ims_vnf.test_vnf(),
+ {'status': 'PASS', 'result': 'vims_test_result'})
+
+ def test_download_and_add_image_on_glance_incorrect_url(self):
+ with mock.patch('functest.opnfv_tests.vnf.ims.cloudify_ims.'
+ 'os.makedirs'), \
+ mock.patch('functest.opnfv_tests.vnf.ims.cloudify_ims.'
+ 'ft_utils.download_url',
+ return_value=False):
+ resp = cloudify_ims.download_and_add_image_on_glance(self.
+ glance_client,
+ 'image_name',
+ 'http://url',
+ 'data_dir')
+ self.assertEqual(resp, False)
+
+ def test_download_and_add_image_on_glance_image_creation_failure(self):
+ with mock.patch('functest.opnfv_tests.vnf.ims.cloudify_ims.'
+ 'os.makedirs'), \
+ mock.patch('functest.opnfv_tests.vnf.ims.cloudify_ims.'
+ 'ft_utils.download_url',
+ return_value=True), \
+ mock.patch('functest.opnfv_tests.vnf.ims.cloudify_ims.'
+ 'os_utils.create_glance_image',
+ return_value=''):
+ resp = cloudify_ims.download_and_add_image_on_glance(self.
+ glance_client,
+ 'image_name',
+ 'http://url',
+ 'data_dir')
+ self.assertEqual(resp, False)
+
+
+if __name__ == "__main__":
+ unittest.main(verbosity=2)
diff --git a/functest/tests/unit/opnfv_tests/vnf/ims/test_orchestrator_cloudify.py b/functest/tests/unit/opnfv_tests/vnf/ims/test_orchestrator_cloudify.py
new file mode 100644
index 000000000..620b0216f
--- /dev/null
+++ b/functest/tests/unit/opnfv_tests/vnf/ims/test_orchestrator_cloudify.py
@@ -0,0 +1,122 @@
+#!/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.opnfv_tests.vnf.ims import orchestrator_cloudify
+
+
+class ImsVnfTesting(unittest.TestCase):
+
+ logging.disable(logging.CRITICAL)
+
+ def setUp(self):
+ self.orchestrator = orchestrator_cloudify.Orchestrator('test_dir')
+ self.bp = {'file_name': 'test_file',
+ 'destination_folder': 'test_folder',
+ 'url': 'test_url',
+ 'branch': 'test_branch'}
+
+ def test_download_manager_blueprint_download_blueprint_failed(self):
+ self.orchestrator.manager_blueprint = False
+ with mock.patch.object(self.orchestrator, '_download_blueprints',
+ return_value=False), \
+ mock.patch('functest.opnfv_tests.vnf.ims.orchestrator_cloudify.'
+ 'exit') as mock_exit:
+ self.orchestrator.download_manager_blueprint('test_url',
+ 'test_branch')
+ mock_exit.assert_any_call(-1)
+
+ def test_download_manager_blueprint_download_blueprint_passed(self):
+ self.orchestrator.manager_blueprint = False
+ with mock.patch.object(self.orchestrator, '_download_blueprints',
+ return_value=True):
+ self.orchestrator.download_manager_blueprint('test_url',
+ 'test_branch')
+ self.assertEqual(self.orchestrator.manager_blueprint,
+ True)
+
+ def test_deploy_manager_failed(self):
+ self.orchestrator.manager_blueprint = True
+ with mock.patch('__builtin__.open', mock.mock_open()), \
+ mock.patch('functest.opnfv_tests.vnf.ims.orchestrator_cloudify.'
+ 'os.remove'), \
+ mock.patch('functest.opnfv_tests.vnf.ims.orchestrator_cloudify.'
+ 'execute_command', return_value='error'):
+ self.assertEqual(self.orchestrator.deploy_manager(),
+ 'error')
+ self.assertEqual(self.orchestrator.manager_up,
+ False)
+
+ def test_deploy_manager_passed(self):
+ self.orchestrator.manager_blueprint = True
+ with mock.patch('__builtin__.open', mock.mock_open()), \
+ mock.patch('functest.opnfv_tests.vnf.ims.orchestrator_cloudify.'
+ 'os.remove'), \
+ mock.patch('functest.opnfv_tests.vnf.ims.orchestrator_cloudify.'
+ 'execute_command', return_value=''):
+ self.orchestrator.deploy_manager()
+ self.assertEqual(self.orchestrator.manager_up,
+ True)
+
+ def test_undeploy_manager_passed(self):
+ with mock.patch('functest.opnfv_tests.vnf.ims.orchestrator_cloudify.'
+ 'execute_command', return_value=''):
+ self.orchestrator.deploy_manager()
+ self.assertEqual(self.orchestrator.manager_up,
+ False)
+
+ def test_dwnld_upload_and_depl_blueprint_dwnld_blueprint_failed(self):
+ with mock.patch.object(self.orchestrator, '_download_blueprints',
+ return_value=False), \
+ mock.patch('functest.opnfv_tests.vnf.ims.orchestrator_cloudify.'
+ 'exit', side_effect=Exception) as mock_exit, \
+ self.assertRaises(Exception):
+ self.orchestrator.download_upload_and_deploy_blueprint(self.bp,
+ 'cfig',
+ 'bpn',
+ 'dpn')
+ mock_exit.assert_any_call(-1)
+
+ def test_dwnld_upload_and_depl_blueprint_failed(self):
+ with mock.patch.object(self.orchestrator, '_download_blueprints',
+ return_value=True), \
+ mock.patch('__builtin__.open', mock.mock_open()), \
+ mock.patch('functest.opnfv_tests.vnf.ims.orchestrator_cloudify.'
+ 'execute_command', return_value='error'):
+ r = self.orchestrator.download_upload_and_deploy_blueprint(self.bp,
+ 'cfig',
+ 'bpn',
+ 'dpn')
+ self.assertEqual(r, 'error')
+
+ def test__download_blueprints_failed(self):
+ with mock.patch('functest.opnfv_tests.vnf.ims.orchestrator_cloudify.'
+ 'shutil.rmtree'), \
+ mock.patch('functest.opnfv_tests.vnf.ims.orchestrator_cloudify.'
+ 'Repo.clone_from', side_effect=Exception):
+ self.assertEqual(self.orchestrator._download_blueprints('bp_url',
+ 'branch',
+ 'dest'),
+ False)
+
+ def test__download_blueprints_passed(self):
+ with mock.patch('functest.opnfv_tests.vnf.ims.orchestrator_cloudify.'
+ 'shutil.rmtree'), \
+ mock.patch('functest.opnfv_tests.vnf.ims.orchestrator_cloudify.'
+ 'Repo.clone_from'):
+ self.assertEqual(self.orchestrator._download_blueprints('bp_url',
+ 'branch',
+ 'dest'),
+ True)
+
+
+if __name__ == "__main__":
+ unittest.main(verbosity=2)
diff --git a/functest/tests/unit/utils/test_openstack_utils.py b/functest/tests/unit/utils/test_openstack_utils.py
index 447271fc6..ef3764cc5 100644
--- a/functest/tests/unit/utils/test_openstack_utils.py
+++ b/functest/tests/unit/utils/test_openstack_utils.py
@@ -104,7 +104,6 @@ class OSUtilsTesting(unittest.TestCase):
'servers.create.return_value': self.instance,
'flavors.list.return_value': [self.flavor],
'flavors.find.return_value': self.flavor,
- 'flavors.list.return_value': [self.flavor],
'servers.add_floating_ip.return_value': mock.Mock(),
'servers.force_delete.return_value': mock.Mock(),
'aggregates.list.return_value': [self.aggregate],
@@ -162,6 +161,15 @@ class OSUtilsTesting(unittest.TestCase):
}
self.cinder_client.configure_mock(**attrs)
+ self.resource = mock.Mock()
+ attrs = {'id': 'resource_test_id',
+ 'name': 'resource_test_name'
+ }
+
+ self.heat_client = mock.Mock()
+ attrs = {'resources.get.return_value': self.resource}
+ self.heat_client.configure_mock(**attrs)
+
mock_obj = mock.Mock()
attrs = {'id': 'tenant_id',
'name': 'test_tenant'}
@@ -543,6 +551,36 @@ class OSUtilsTesting(unittest.TestCase):
mock_glan_client.assert_called_once_with('3',
session=mock_session_obj)
+ @mock.patch('functest.utils.openstack_utils.os.getenv',
+ return_value=None)
+ def test_get_heat_client_version_missing_env(self, mock_os_getenv):
+ self.assertEqual(openstack_utils.get_heat_client_version(),
+ openstack_utils.DEFAULT_HEAT_API_VERSION)
+
+ @mock.patch('functest.utils.openstack_utils.logger.info')
+ @mock.patch('functest.utils.openstack_utils.os.getenv', return_value='1')
+ def test_get_heat_client_version_default(self, mock_os_getenv,
+ mock_logger_info):
+ self.assertEqual(openstack_utils.get_heat_client_version(), '1')
+ mock_logger_info.assert_called_once_with(
+ "OS_ORCHESTRATION_API_VERSION is set in env as '%s'", '1')
+
+ def test_get_heat_client(self):
+ mock_heat_obj = mock.Mock()
+ mock_session_obj = mock.Mock()
+ with mock.patch('functest.utils.openstack_utils'
+ '.get_heat_client_version', return_value='1'), \
+ mock.patch('functest.utils.openstack_utils'
+ '.heatclient.Client',
+ return_value=mock_heat_obj) \
+ as mock_heat_client, \
+ mock.patch('functest.utils.openstack_utils.get_session',
+ return_value=mock_session_obj):
+ self.assertEqual(openstack_utils.get_heat_client(),
+ mock_heat_obj)
+ mock_heat_client.assert_called_once_with('1',
+ session=mock_session_obj)
+
def test_get_instances_default(self):
self.assertEqual(openstack_utils.get_instances(self.nova_client),
[self.instance])
@@ -1700,6 +1738,24 @@ class OSUtilsTesting(unittest.TestCase):
'user_id'))
self.assertTrue(mock_logger_error.called)
+ def test_get_resource_default(self):
+ with mock.patch('functest.utils.openstack_utils.'
+ 'is_keystone_v3', return_value=True):
+ self.assertEqual(openstack_utils.
+ get_resource(self.heat_client,
+ 'stack_id',
+ 'resource'),
+ self.resource)
+
+ @mock.patch('functest.utils.openstack_utils.logger.error')
+ def test_get_resource_exception(self, mock_logger_error):
+ self.assertEqual(openstack_utils.
+ get_resource(Exception,
+ 'stack_id',
+ 'resource'),
+ None)
+ self.assertTrue(mock_logger_error.called)
+
if __name__ == "__main__":
unittest.main(verbosity=2)
diff --git a/functest/utils/config.py b/functest/utils/config.py
index 84166c1d3..b5b845010 100644..100755
--- a/functest/utils/config.py
+++ b/functest/utils/config.py
@@ -2,26 +2,25 @@ import os
import yaml
+import env
+
class Config(object):
def __init__(self):
- if 'CONFIG_FUNCTEST_YAML' not in os.environ:
- raise Exception('CONFIG_FUNCTEST_YAML not configed')
- self.config_functest = os.environ['CONFIG_FUNCTEST_YAML']
try:
- with open(self.config_functest) as f:
+ with open(env.ENV.CONFIG_FUNCTEST_YAML) as f:
self.functest_yaml = yaml.safe_load(f)
self._parse(None, self.functest_yaml)
- except:
- raise Exception('Parse {} failed'.format(self.config_functest))
+ except Exception as error:
+ raise Exception('Parse config failed: {}'.format(str(error)))
self._set_others()
def _parse(self, attr_now, left_parametes):
for param_n, param_v in left_parametes.iteritems():
attr_further = self._get_attr_further(attr_now, param_n)
- if not isinstance(param_v, dict):
+ if attr_further:
self.__setattr__(attr_further, param_v)
- else:
+ if isinstance(param_v, dict):
self._parse(attr_further, param_v)
def _get_attr_further(self, attr_now, next):
@@ -33,3 +32,8 @@ 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/openstack_utils.py b/functest/utils/openstack_utils.py
index 3093cb558..e33af63b4 100755
--- a/functest/utils/openstack_utils.py
+++ b/functest/utils/openstack_utils.py
@@ -18,6 +18,7 @@ from keystoneauth1 import loading
from keystoneauth1 import session
from cinderclient import client as cinderclient
from glanceclient import client as glanceclient
+from heatclient import client as heatclient
from novaclient import client as novaclient
from keystoneclient import client as keystoneclient
from neutronclient.neutron import client as neutronclient
@@ -28,6 +29,7 @@ import functest.utils.functest_utils as ft_utils
logger = ft_logger.Logger("openstack_utils").getLogger()
DEFAULT_API_VERSION = '2'
+DEFAULT_HEAT_API_VERSION = '1'
# *********************************************
@@ -241,6 +243,20 @@ def get_glance_client(other_creds={}):
return glanceclient.Client(get_glance_client_version(), session=sess)
+def get_heat_client_version():
+ api_version = os.getenv('OS_ORCHESTRATION_API_VERSION')
+ if api_version is not None:
+ logger.info("OS_ORCHESTRATION_API_VERSION is set in env as '%s'",
+ api_version)
+ return api_version
+ return DEFAULT_HEAT_API_VERSION
+
+
+def get_heat_client(other_creds={}):
+ sess = get_session(other_creds)
+ return heatclient.Client(get_heat_client_version(), session=sess)
+
+
# *********************************************
# NOVA
# *********************************************
@@ -985,36 +1001,43 @@ def create_security_group(neutron_client, sg_name, sg_description):
def create_secgroup_rule(neutron_client, sg_id, direction, protocol,
port_range_min=None, port_range_max=None):
- if port_range_min is None and port_range_max is None:
- json_body = {'security_group_rule': {'direction': direction,
- 'security_group_id': sg_id,
- 'protocol': protocol}}
- elif port_range_min is not None and port_range_max is not None:
- json_body = {'security_group_rule': {'direction': direction,
- 'security_group_id': sg_id,
- 'port_range_min': port_range_min,
- 'port_range_max': port_range_max,
- 'protocol': protocol}}
+ # We create a security group in 2 steps
+ # 1 - we check the format and set the json body accordingly
+ # 2 - we call neturon client to create the security group
+
+ # Format check
+ json_body = {'security_group_rule': {'direction': direction,
+ 'security_group_id': sg_id,
+ 'protocol': protocol}}
+ # parameters may be
+ # - both None => we do nothing
+ # - both Not None => we add them to the json description
+ # but one cannot be None is the other is not None
+ if (port_range_min is not None and port_range_max is not None):
+ # add port_range in json description
+ json_body['security_group_rule']['port_range_min'] = port_range_min
+ json_body['security_group_rule']['port_range_max'] = port_range_max
+ logger.debug("Security_group format set (port range included)")
else:
- logger.error("Error [create_secgroup_rule(neutron_client, '%s', '%s', "
- "'%s', '%s', '%s', '%s')]:" % (neutron_client,
- sg_id, direction,
- port_range_min,
- port_range_max,
- protocol),
- " Invalid values for port_range_min, port_range_max")
- return False
+ # either both port range are set to None => do nothing
+ # or one is set but not the other => log it and return False
+ if port_range_min is None and port_range_max is None:
+ logger.debug("Security_group format set (no port range mentioned)")
+ else:
+ logger.error("Bad security group format."
+ "One of the port range is not properly set:"
+ "range min: {},"
+ "range max: {}".format(port_range_min,
+ port_range_max))
+ return False
+
+ # Create security group using neutron client
try:
neutron_client.create_security_group_rule(json_body)
return True
- except Exception, e:
- logger.error("Error [create_secgroup_rule(neutron_client, '%s', '%s', "
- "'%s', '%s', '%s', '%s')]: %s" % (neutron_client,
- sg_id,
- direction,
- port_range_min,
- port_range_max,
- protocol, e))
+ except:
+ logger.exception("Impossible to create_security_group_rule,"
+ "security group rule probably already exists")
return False
@@ -1383,3 +1406,15 @@ def delete_user(keystone_client, user_id):
logger.error("Error [delete_user(keystone_client, '%s')]: %s"
% (user_id, e))
return False
+
+
+# *********************************************
+# HEAT
+# *********************************************
+def get_resource(heat_client, stack_id, resource):
+ try:
+ resources = heat_client.resources.get(stack_id, resource)
+ return resources
+ except Exception, e:
+ logger.error("Error [get_resource]: %s" % e)
+ return None
diff --git a/requirements.txt b/requirements.txt
index 68b889b35..ee629eab8 100644
--- a/requirements.txt
+++ b/requirements.txt
@@ -9,6 +9,7 @@ pyyaml==3.10
gitpython==1.0.1
python-openstackclient==2.3.0
python-ceilometerclient==2.6.2
+python-heatclient==1.7.0
python-keystoneclient==3.5.0
python-neutronclient==6.0.0
python-novaclient==6.0.0
diff --git a/run_unit_tests.sh b/run_unit_tests.sh
index d60a2d623..8e02880a6 100755
--- a/run_unit_tests.sh
+++ b/run_unit_tests.sh
@@ -42,6 +42,7 @@ nosetests --with-xunit \
--cover-package=functest.cli \
--cover-package=functest.core.testcase_base \
--cover-package=functest.opnfv_tests.sdn.odl.odl \
+ --cover-package=functest.opnfv_tests.vnf.ims \
--cover-package=functest.utils \
--cover-package=functest.opnfv_tests.openstack.rally \
--cover-xml \
diff --git a/test-requirements.txt b/test-requirements.txt
index 96b276780..471e9c30a 100644
--- a/test-requirements.txt
+++ b/test-requirements.txt
@@ -14,6 +14,7 @@ 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
@@ -23,4 +24,5 @@ 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