Merge "Adopt TestcaseBase for ONOS and ONOS SFC"
authorJose Lausuch <jose.lausuch@ericsson.com>
Wed, 1 Mar 2017 22:13:28 +0000 (22:13 +0000)
committerGerrit Code Review <gerrit@opnfv.org>
Wed, 1 Mar 2017 22:13:28 +0000 (22:13 +0000)
42 files changed:
docker/Dockerfile
docker/Dockerfile.aarch64
docker/add_images.sh [new file with mode: 0755]
docs/internship/testapi_evolution/index.rst [deleted file]
docs/release/release-notes/functest-release.rst [moved from docs/release-notes/functest-release.rst with 100% similarity]
docs/release/release-notes/index.rst [moved from docs/release-notes/index.rst with 100% similarity]
docs/testing/developer/devguide/index.rst [moved from docs/devguide/index.rst with 97% similarity]
docs/testing/developer/internship/security_group/index.rst [moved from docs/internship/security_group/index.rst with 100% similarity]
docs/testing/developer/internship/testapi_evolution/index.rst [new file with mode: 0644]
docs/testing/developer/internship/unit_tests/index.rst [moved from docs/internship/unit_tests/index.rst with 100% similarity]
docs/testing/developer/internship/vnf_catalog/index.rst [moved from docs/internship/vnf_catalog/index.rst with 100% similarity]
docs/testing/user/configguide/configguide.rst [moved from docs/configguide/configguide.rst with 100% similarity]
docs/testing/user/configguide/index.rst [moved from docs/configguide/index.rst with 100% similarity]
docs/testing/user/userguide/index.rst [moved from docs/userguide/index.rst with 100% similarity]
docs/testing/user/userguide/introduction.rst [moved from docs/userguide/introduction.rst with 100% similarity]
docs/testing/user/userguide/runfunctest.rst [moved from docs/userguide/runfunctest.rst with 99% similarity]
docs/testing/user/userguide/troubleshooting.rst [moved from docs/userguide/troubleshooting.rst with 99% similarity]
functest/ci/config_aarch64_patch.yaml [new file with mode: 0644]
functest/ci/config_functest.yaml
functest/ci/config_patch.yaml
functest/ci/prepare_env.py
functest/ci/rally_aarch64_patch.conf [new file with mode: 0644]
functest/ci/testcases.yaml
functest/opnfv_tests/openstack/rally/scenario/templates/server_with_ports.yaml.template
functest/opnfv_tests/openstack/rally/scenario/templates/server_with_volume.yaml.template
functest/opnfv_tests/openstack/tempest/custom_tests/blacklist.txt
functest/opnfv_tests/openstack/tempest/custom_tests/test_list.txt [new file with mode: 0644]
functest/opnfv_tests/openstack/tempest/tempest.py
functest/opnfv_tests/vnf/ims/cloudify_ims.py
functest/opnfv_tests/vnf/router/__init__.py [new file with mode: 0755]
functest/opnfv_tests/vnf/router/vyos_vrouter.py [new file with mode: 0755]
functest/tests/unit/opnfv_tests/vnf/__init__.py [new file with mode: 0644]
functest/tests/unit/opnfv_tests/vnf/ims/__init__.py [new file with mode: 0644]
functest/tests/unit/opnfv_tests/vnf/ims/test_clearwater.py [new file with mode: 0644]
functest/tests/unit/opnfv_tests/vnf/ims/test_cloudify_ims.py [new file with mode: 0644]
functest/tests/unit/opnfv_tests/vnf/ims/test_orchestrator_cloudify.py [new file with mode: 0644]
functest/tests/unit/utils/test_openstack_utils.py
functest/utils/config.py [changed mode: 0644->0755]
functest/utils/openstack_utils.py
requirements.txt
run_unit_tests.sh
test-requirements.txt

index f59e1f7..de47e15 100644 (file)
@@ -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
index bf8e361..a469801 100644 (file)
@@ -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 (executable)
index 0000000..af2956c
--- /dev/null
@@ -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 (file)
index f2583e2..0000000
+++ /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
-
similarity index 97%
rename from docs/devguide/index.rst
rename to docs/testing/developer/devguide/index.rst
index 42ad044..eee0136 100644 (file)
@@ -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/testing/developer/internship/testapi_evolution/index.rst b/docs/testing/developer/internship/testapi_evolution/index.rst
new file mode 100644 (file)
index 0000000..6a1cde7
--- /dev/null
@@ -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
similarity index 99%
rename from docs/userguide/runfunctest.rst
rename to docs/testing/user/userguide/runfunctest.rst
index b5c7191..e7ab84b 100644 (file)
@@ -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'...
similarity index 99%
rename from docs/userguide/troubleshooting.rst
rename to docs/testing/user/userguide/troubleshooting.rst
index 1b7bf9b..8455019 100644 (file)
@@ -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 (file)
index 0000000..9a345e3
--- /dev/null
@@ -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
index a3eebab..402e299 100755 (executable)
@@ -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
 
index 46064a0..d984a3f 100755 (executable)
@@ -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:
index 5a9f99c..724ea14 100755 (executable)
@@ -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 (file)
index 0000000..a49588b
--- /dev/null
@@ -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
index 1e5ba75..77cd1ae 100755 (executable)
@@ -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'
@@ -317,6 +317,18 @@ tiers:
                 run:
                     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'
@@ -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'
index 909f45d..ed5e61f 100644 (file)
@@ -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
index 826ca9d..116b5bb 100644 (file)
@@ -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
index 0a4256c..fcdfe22 100644 (file)
@@ -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 (file)
index 0000000..ac4e372
--- /dev/null
@@ -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
index 37b5c0e..4c96500 100644 (file)
@@ -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):
index 584d780..c2c251a 100644 (file)
@@ -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 (executable)
index 0000000..e69de29
diff --git a/functest/opnfv_tests/vnf/router/vyos_vrouter.py b/functest/opnfv_tests/vnf/router/vyos_vrouter.py
new file mode 100755 (executable)
index 0000000..94a3ecf
--- /dev/null
@@ -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 (file)
index 0000000..e69de29
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 (file)
index 0000000..e69de29
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 (file)
index 0000000..527f12e
--- /dev/null
@@ -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 (file)
index 0000000..e25816f
--- /dev/null
@@ -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 (file)
index 0000000..620b021
--- /dev/null
@@ -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)
index 447271f..ef3764c 100644 (file)
@@ -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)
old mode 100644 (file)
new mode 100755 (executable)
index 84166c1..b5b8450
@@ -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
index 3093cb5..e33af63 100755 (executable)
@@ -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
index 68b889b..ee629ea 100644 (file)
@@ -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
index d60a2d6..8e02880 100755 (executable)
@@ -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 \
index 96b2767..471e9c3 100644 (file)
@@ -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