If not, see <http://creativecommons.org/licenses/by/4.0/>.
=============================================
-OPNFV Euphrates 5.0 release note for Functest
+OPNFV Euphrates 5.1 release note for Functest
=============================================
Abstract
| **Project** | functest |
| | |
+--------------------------------------+--------------------------------------+
-| **Repo/tag** | opnfv-5.0.0 |
+| **Repo/tag** | opnfv-5.1.0 |
| | |
+--------------------------------------+--------------------------------------+
-| **Release designation** | Euphrates initial release |
+| **Release designation** | Euphrates 5.1 release |
| | |
+--------------------------------------+--------------------------------------+
-| **Release date** | October 20th 2017 |
+| **Release date** | December 15th 2017 |
| | |
+--------------------------------------+--------------------------------------+
-| **Purpose of the delivery** | Euphrates first release |
+| **Purpose of the delivery** | Euphrates second release |
| | |
+--------------------------------------+--------------------------------------+
Functest Docker images:
- * https://hub.docker.com/r/opnfv/functest
* https://hub.docker.com/r/opnfv/functest-healthcheck
* https://hub.docker.com/r/opnfv/functest-smoke
* https://hub.docker.com/r/opnfv/functest-features
* https://hub.docker.com/r/opnfv/testapi
-Docker tag to be pulled: opnfv-5.0.0
+Docker tag to be pulled:
+ * amd64: amd64-opnfv-5.1.0
+ * arm64: arm64-opnfv-5.1.0
Documents
---------
or tiers and must be run from the corresponding container. For example, to run the test case healthcheck, the image
opnfv/functest-healthcheck shall be used. The tiers and the tests within them are explained in detail in the User Guide.
-For ARM (aarch64), the former Ubuntu image opnfv/functest shall be used since there are not any Alpine images built
-for this architecture yet. It will probably be supported for Euphrates 5.1.
+The former Ubuntu image is not longer maintained.
The Parser test case has its own dedicated Docker image since it requires libraries released for OpenStack Pike and
Euphrates is based on Ocata.
This could be considered as a first step towards a pseudo micro services approach where the different test projects could expose and
consume APIs to the other test projects.
+Euphrates 5.1 improvements
+==========================
-Euphrates known restrictions/issues
-===================================
+* Alpine images are now supported for ARM (arm64).
+* Added Vyos_router test case.
+* Updated of Rally 0.9.1 and fixed some bugs in cinder scenarios.
+* Patch to allow building containers from a gerrit change.
+* Selection of a subset of SNAPS test cases.
+* Reorder VNF test cases and adjust timeouts in VNFs.
+
+
+
+Euphrates 5.1 known restrictions/issues
+=======================================
+--------------+-----------+----------------------------------------------+
| Installer | Scenario | Issue |
+==============+===========+==============================================+
-| fuel@aarch64 | any | Alpine containers not supported yet for ARM |
-| | | The former Ubuntu Docker image shall be |
-| | | still used for this architecture. |
-+--------------+-----------+----------------------------------------------+
| fuel@aarch64 | any | VNF tier not supported yet. |
+--------------+-----------+----------------------------------------------+
| | | The test cases belonging to the VNF tier |
Test results
============
-The Functest scenario status on October 20, 2017 can be seen on
+The Functest scenario status on December 15, 2017 can be seen on
http://testresults.opnfv.org/functest/euphrates/
Test logs are available in:
+---
Show credentials
This api offers the interface to show credentials.
The credentials dict will be returned.
---
tags:
- - Creds
+ - Creds
definitions:
- Credentials:
- type: object
- properties:
- creds_name:
- $ref: '#/definitions/Name'
- Name:
- type: dict
+ Credentials:
+ type: object
+ properties:
+ creds_name:
+ $ref: '#/definitions/Name'
+ Name:
+ type: dict
responses:
- 200:
- description: Show credentials
- schema:
- $ref: '#/definitions/Credentials'
- examples:
- "OS_AUTH_URL": "https://192.16.1.222:5000/v3"
- "OS_AUTH_VERSION": "3"
- "OS_CACERT": "/home/opnfv/functest/conf/os_cacert"
- "OS_ENDPOINT_TYPE": "publicURL"
- "OS_IDENTITY_API_VERSION": "3"
- "OS_INTERFACE": "publicURL"
- "OS_NO_CACHE": "1"
- "OS_PASSWORD": "990232e0885da343ac805528522d"
- "OS_PROJECT_DOMAIN_NAME": "Default"
- "OS_PROJECT_NAME": "admin"
- "OS_REGION_NAME": "RegionOne"
- "OS_TENANT_NAME": "admin"
- "OS_USERNAME": "admin"
- "OS_USER_DOMAIN_NAME": "Default"
+ 200:
+ description: Show credentials
+ schema:
+ $ref: '#/definitions/Credentials'
+ examples:
+ "OS_AUTH_URL": "https://192.16.1.222:5000/v3"
+ "OS_AUTH_VERSION": "3"
+ "OS_CACERT": "/home/opnfv/functest/conf/os_cacert"
+ "OS_ENDPOINT_TYPE": "publicURL"
+ "OS_IDENTITY_API_VERSION": "3"
+ "OS_INTERFACE": "publicURL"
+ "OS_NO_CACHE": "1"
+ "OS_PASSWORD": "990232e0885da343ac805528522d"
+ "OS_PROJECT_DOMAIN_NAME": "Default"
+ "OS_PROJECT_NAME": "admin"
+ "OS_REGION_NAME": "RegionOne"
+ "OS_TENANT_NAME": "admin"
+ "OS_USERNAME": "admin"
+ "OS_USER_DOMAIN_NAME": "Default"
+---
Update openrc
This api offers the interface to Update openstack.creds.
-
-action: update_openrc
---
tags:
- - Creds
+ - Creds
parameters:
- - in: body
- name: body
- description: this is the input json dict
- schema:
- required:
- - action
- - args
- properties:
- action:
- type: string
- description: this is action for creds
- default: update_openrc
- args:
- schema:
- required:
- - openrc
- properties:
- openrc:
- type: string
- description: this is the test case name
- default:
- "OS_AUTH_URL": "http://192.16.1.222:5000/v3"
- "OS_ENDPOINT_TYPE": "publicURL"
- "OS_IDENTITY_API_VERSION": "3"
- "OS_INTERFACE": "publicURL"
- "OS_PASSWORD": "admn"
- "OS_PROJECT_DOMAIN_NAME": "Default"
- "OS_PROJECT_NAME": "admin"
- "OS_REGION_NAME": "RegionOne"
- "OS_TENANT_NAME": "admin"
- "OS_USERNAME": "admin"
- "OS_USER_DOMAIN_NAME": "Default"
+ - in: body
+ name: body
+ description: this is the input json dict
+ schema:
+ required:
+ - action
+ - args
+ properties:
+ action:
+ type: string
+ description: this is action for creds
+ default: update_openrc
+ args:
+ schema:
+ required:
+ - openrc
+ properties:
+ openrc:
+ type: string
+ description: this is the test case name
+ default:
+ "OS_AUTH_URL": "http://192.16.1.222:5000/v3"
+ "OS_ENDPOINT_TYPE": "publicURL"
+ "OS_IDENTITY_API_VERSION": "3"
+ "OS_INTERFACE": "publicURL"
+ "OS_PASSWORD": "admn"
+ "OS_PROJECT_DOMAIN_NAME": "Default"
+ "OS_PROJECT_NAME": "admin"
+ "OS_REGION_NAME": "RegionOne"
+ "OS_TENANT_NAME": "admin"
+ "OS_USERNAME": "admin"
+ "OS_USER_DOMAIN_NAME": "Default"
definitions:
- Credentials:
- type: object
- properties:
- creds_name:
- $ref: '#/definitions/Name'
- Name:
- type: dict
+ Credentials:
+ type: object
+ properties:
+ creds_name:
+ $ref: '#/definitions/Name'
+ Name:
+ type: dict
responses:
- 200:
- description: Update openrc
- schema:
- $ref: '#/definitions/Credentials'
- examples:
- 'status': 0
- 'result': 'Update openrc successfully'
+ 200:
+ description: Update openrc
+ schema:
+ $ref: '#/definitions/Credentials'
+ examples:
+ 'status': 0
+ 'result': 'Update openrc successfully'
+---
Show environment
This api offers the interface to show environment.
The environment dict will be returned.
---
tags:
- - Envs
+ - Envs
definitions:
- Environment:
- type: object
- properties:
- creds_name:
- $ref: '#/definitions/Name'
- Name:
- type: dict
+ Environment:
+ type: object
+ properties:
+ creds_name:
+ $ref: '#/definitions/Name'
+ Name:
+ type: dict
responses:
- 200:
- description: Show environment
- schema:
- $ref: '#/definitions/Environment'
- examples:
- "DEBUG FLAG": "false"
- "INSTALLER": "compass, 192.168.200.2"
- "POD": "unknown_pod"
- "SCENARIO": "os-nosdn-nofeature-noha"
- "STATUS": "ready"
+ 200:
+ description: Show environment
+ schema:
+ $ref: '#/definitions/Environment'
+ examples:
+ "DEBUG FLAG": "false"
+ "INSTALLER": "compass, 192.168.200.2"
+ "POD": "unknown_pod"
+ "SCENARIO": "os-nosdn-nofeature-noha"
+ "STATUS": "ready"
+---
Update hosts info
This api offers the interface to update hosts info.
-
-action: update_hosts
---
tags:
- - Envs
+ - Envs
parameters:
- - in: body
- name: body
- description: this is the input json dict
- schema:
- required:
- - action
- - args
- properties:
- action:
- type: string
- description: this is action for envs
- default: update_hosts
- args:
- type: string
- description: Hosts info to be updated
- default:
- "identity.ac.dz.com": "8.20.11.22"
- "image.ac.dz.com": "8.20.11.22"
+ - in: body
+ name: body
+ description: this is the input json dict
+ schema:
+ required:
+ - action
+ - args
+ properties:
+ action:
+ type: string
+ description: this is action for envs
+ default: update_hosts
+ args:
+ type: string
+ description: Hosts info to be updated
+ default:
+ "identity.ac.dz.com": "8.20.11.22"
+ "image.ac.dz.com": "8.20.11.22"
definitions:
- Environment:
- type: object
- properties:
- creds_name:
- $ref: '#/definitions/Name'
- Name:
- type: dict
+ Environment:
+ type: object
+ properties:
+ creds_name:
+ $ref: '#/definitions/Name'
+ Name:
+ type: dict
responses:
- 200:
- description: Update hosts info
- schema:
- $ref: '#/definitions/Environment'
- examples:
- 'status': 0
- 'result': 'Update hosts info successfully'
\ No newline at end of file
+ 200:
+ description: Update hosts info
+ schema:
+ $ref: '#/definitions/Environment'
+ examples:
+ 'status': 0
+ 'result': 'Update hosts info successfully'
+---
Get the result of the specified task
This api offers the interface to get the result of the specified task.
-
---
tags:
- - Tasks
+ - Tasks
parameters:
- - name: task_id
- description: task id
- in: path
- type: string
- required: true
+ - name: task_id
+ description: task id
+ in: path
+ type: string
+ required: true
definitions:
- Task:
- type: object
- properties:
- creds_name:
- $ref: '#/definitions/Result'
- Result:
- type: dict
+ Task:
+ type: object
+ properties:
+ creds_name:
+ $ref: '#/definitions/Result'
+ Result:
+ type: dict
responses:
- 200:
- description: Get the result of the specified task
- schema:
- $ref: '#/definitions/Task'
- examples:
- "result": {
- "case_name": "vping_ssh",
- "env_info": {
- "build_tag": null,
- "ci_loop": "weekly",
- "installer": "compass",
- "scenario": "os-nosdn-nofeature-noha" },
- "result": "PASS",
- "task_id": "1a9f3c5d-ce0b-4354-862e-dd08b26fc484"}
- "status": 2
-
+ 200:
+ description: Get the result of the specified task
+ schema:
+ $ref: '#/definitions/Task'
+ examples:
+ "result": {
+ "case_name": "vping_ssh",
+ "env_info": {
+ "build_tag": null,
+ "ci_loop": "weekly",
+ "installer": "compass",
+ "scenario": "os-nosdn-nofeature-noha"},
+ "result": "PASS",
+ "task_id": "1a9f3c5d-ce0b-4354-862e-dd08b26fc484"}
+ "status": 2
+---
Get the log of the specified task
This api offers the interface to get the log of the specified task.
-
---
tags:
- - Tasks
+ - Tasks
parameters:
- - name: task_id
- description: task id
- in: path
- type: string
- required: true
+ - name: task_id
+ description: task id
+ in: path
+ type: string
+ required: true
definitions:
- Task:
- type: object
- properties:
- creds_name:
- $ref: '#/definitions/Result'
- Result:
- type: dict
+ Task:
+ type: object
+ properties:
+ creds_name:
+ $ref: '#/definitions/Result'
+ Result:
+ type: dict
responses:
- 200:
- description: Get the log of the specified task
- schema:
- $ref: '#/definitions/Task'
- examples:
- "result": {
- "data": [
- "2017-09-14 06:46:26,106 - functest.ci.run_tests - DEBUG - Sourcing the OpenStack RC file... ",
- "2017-09-14 06:46:26,107 - functest.ci.run_tests - DEBUG - Test args: connection_check ",
- "2017-09-14 06:46:26,107 - functest.ci.run_tests - INFO - Running test case 'connection_check'... ",
- "..."]}
- "status": 2
-
+ 200:
+ description: Get the log of the specified task
+ schema:
+ $ref: '#/definitions/Task'
+ examples:
+ "result": {
+ "data": [
+ "2017-09-14 06:46:26,106 - functest.ci.run_tests - DEBUG ",
+ "- Sourcing the OpenStack RC file... ",
+ "2017-09-14 06:46:26,107 - functest.ci.run_tests - DEBUG ",
+ "- Test args: connection_check ",
+ "2017-09-14 06:46:26,107 - functest.ci.run_tests - INFO ",
+ "- Running test case 'connection_check'... ",
+ "..."]}
+ "status": 2
+---
Show the info of one testcase
This api offers the interface to show the detailed info of one testcase.
The info of one testcase will be returned.
---
tags:
- - Testcases
+ - Testcases
parameters:
- - name: testcase_name
- description: testcase name
- in: path
- type: string
- required: true
+ - name: testcase_name
+ description: testcase name
+ in: path
+ type: string
+ required: true
definitions:
- Testcases:
- type: object
- properties:
- case_name:
- $ref: '#/definitions/Tests'
- Tests:
- type: dict
+ Testcases:
+ type: object
+ properties:
+ case_name:
+ $ref: '#/definitions/Tests'
+ Tests:
+ type: dict
responses:
- 200:
- description: Show the detailed info of one testcase
- schema:
- $ref: '#/definitions/Testcases'
- examples:
- "testcase": ""
- "blocking":
- "criteria":
- "dependency": {
- "installer": "",
- "scenario": ""
- }
- "description": ""
- "enabled":
+ 200:
+ description: Show the detailed info of one testcase
+ schema:
+ $ref: '#/definitions/Testcases'
+ examples:
+ "testcase": ""
+ "blocking":
+ "criteria":
+ "dependency": {
+ "installer": "",
+ "scenario": ""}
+ "description": ""
+ "enabled":
+---
Run a test case
This api offers the interface to run a test case
-
-action: run_test_case
---
tags:
- - Testcases
+ - Testcases
parameters:
- - in: body
- name: body
- description: this is the input json dict
- schema:
- required:
- - action
- - args
- properties:
- action:
- type: string
- description: this is action for creds
- default: run_test_case
- args:
- schema:
- required:
- - testcase
- properties:
- testcase:
- type: string
- description: this is the test case name
- default:
- vping_ssh
+ - in: body
+ name: body
+ description: this is the input json dict
+ schema:
+ required:
+ - action
+ - args
+ properties:
+ action:
+ type: string
+ description: this is action for creds
+ default: run_test_case
+ args:
+ schema:
+ required:
+ - testcase
+ properties:
+ testcase:
+ type: string
+ description: this is the test case name
+ default:
+ vping_ssh
definitions:
- Testcases:
- type: object
- properties:
- creds_name:
- $ref: '#/definitions/Tests'
- Tests:
- type: dict
+ Testcases:
+ type: object
+ properties:
+ creds_name:
+ $ref: '#/definitions/Tests'
+ Tests:
+ type: dict
responses:
- 200:
- description: Run a test case
- schema:
- $ref: '#/definitions/Testcases'
- examples:
- 'task_id': '94c8ec94-d873-466f-a205-bf592f31ff5b'
- 'testcase': 'vping_ssh'
+ 200:
+ description: Run a test case
+ schema:
+ $ref: '#/definitions/Testcases'
+ examples:
+ 'task_id': '94c8ec94-d873-466f-a205-bf592f31ff5b'
+ 'testcase': 'vping_ssh'
+---
List all test cases
This api offers the interface to list all test cases
The testcases list will be returned
---
tags:
- - Testcases
+ - Testcases
definitions:
- Testcases:
- type: object
- properties:
- creds_name:
- $ref: '#/definitions/Tests'
- Tests:
- type: dict
+ Testcases:
+ type: object
+ properties:
+ creds_name:
+ $ref: '#/definitions/Tests'
+ Tests:
+ type: dict
responses:
- 200:
- description: List all test cases
- schema:
- $ref: '#/definitions/Testcases'
- examples:
- "testcases": []
+ 200:
+ description: List all test cases
+ schema:
+ $ref: '#/definitions/Testcases'
+ examples:
+ "testcases": []
+---
List all testcases within given tier
This api offers the interface to list all testcases within given tier.
All testcases within given tier will be returned.
---
tags:
- - Tiers
+ - Tiers
parameters:
- - name: tier_name
- description: tier name
- in: path
- type: string
- required: true
+ - name: tier_name
+ description: tier name
+ in: path
+ type: string
+ required: true
definitions:
- Testcases:
- type: object
- properties:
- creds_name:
- $ref: '#/definitions/Tests'
- Tests:
- type: dict
+ Testcases:
+ type: object
+ properties:
+ creds_name:
+ $ref: '#/definitions/Tests'
+ Tests:
+ type: dict
responses:
- 200:
- description: List all testcases within given tier
- schema:
- $ref: '#/definitions/Testcases'
- examples:
- "tier": ""
- "testcases": []
+ 200:
+ description: List all testcases within given tier
+ schema:
+ $ref: '#/definitions/Testcases'
+ examples:
+ "tier": ""
+ "testcases": []
+---
Show the info of one tier
This api offers the interface to show the detailed info of one tier.
The info of one tier will be returned.
---
tags:
- - Tiers
+ - Tiers
parameters:
- - name: tier_name
- description: tier name
- in: path
- type: string
- required: true
+ - name: tier_name
+ description: tier name
+ in: path
+ type: string
+ required: true
definitions:
- Tiers:
- type: object
- properties:
- creds_name:
- $ref: '#/definitions/Name'
- Name:
- type: string
+ Tiers:
+ type: object
+ properties:
+ creds_name:
+ $ref: '#/definitions/Name'
+ Name:
+ type: string
responses:
- 200:
- description: Show the detailed info of one tier
- schema:
- $ref: '#/definitions/Tiers'
- examples:
- "tier": ""
- "ci_loop": ""
- "description": ""
- "order":
- "testcases": []
+ 200:
+ description: Show the detailed info of one tier
+ schema:
+ $ref: '#/definitions/Tiers'
+ examples:
+ "tier": ""
+ "ci_loop": ""
+ "description": ""
+ "order":
+ "testcases": []
+---
List all tiers
This api offers the interface to list all tiers.
The tiers list will be returned.
---
tags:
- - Tiers
+ - Tiers
definitions:
- Tiers:
- type: object
- properties:
- creds_name:
- $ref: '#/definitions/Tier'
- Tier:
- type: dict
+ Tiers:
+ type: object
+ properties:
+ creds_name:
+ $ref: '#/definitions/Tier'
+ Tier:
+ type: dict
responses:
- 200:
- description: List all tiers
- schema:
- $ref: '#/definitions/Tiers'
- examples:
- "tiers": ""
+ 200:
+ description: List all tiers
+ schema:
+ $ref: '#/definitions/Tiers'
+ examples:
+ "tiers": ""
snaps:
images:
glance_tests:
- disk_file: /
- home/opnfv/functest/images/cirros-d161201-aarch64-disk.img
+ disk_file:
+ /home/opnfv/functest/images/cirros-d161201-aarch64-disk.img
extra_properties:
hw_firmware_type: 'uefi'
short_id: 'ubuntu16.04'
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.5-x86_64-lxc.tar.gz
- disk_format: raw
fdio:
general:
flavor_extra_specs: {'hw:mem_page_size':'large'}
import prettytable
import six
-import yaml
import functest.ci.tier_builder as tb
import functest.core.testcase as testcase
CONFIG_FUNCTEST_PATH = pkg_resources.resource_filename(
'functest', 'ci/config_functest.yaml')
-CONFIG_PATCH_PATH = pkg_resources.resource_filename(
- 'functest', 'ci/config_patch.yaml')
-CONFIG_AARCH64_PATCH_PATH = pkg_resources.resource_filename(
- 'functest', 'ci/config_aarch64_patch.yaml')
-# set the architecture to default
-pod_arch = os.getenv("POD_ARCH", None)
-arch_filter = ['aarch64']
class Result(enum.Enum):
CONST.__getattribute__('DEPLOY_SCENARIO'),
pkg_resources.resource_filename('functest', 'ci/testcases.yaml'))
- @staticmethod
- def update_config_file():
- Runner.patch_file(CONFIG_PATCH_PATH)
-
- if pod_arch and pod_arch in arch_filter:
- Runner.patch_file(CONFIG_AARCH64_PATCH_PATH)
-
- @staticmethod
- 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 patch_file:
- if key in CONST.__getattribute__('DEPLOY_SCENARIO'):
- new_functest_yaml = dict(ft_utils.merge_dicts(
- ft_utils.get_functest_yaml(), patch_file[key]))
- updated = True
-
- if updated:
- os.remove(CONFIG_FUNCTEST_PATH)
- with open(CONFIG_FUNCTEST_PATH, "w") as f:
- f.write(yaml.dump(new_functest_yaml, default_style='"'))
-
@staticmethod
def source_rc_file():
rc_file = CONST.__getattribute__('openstack_creds')
self.run_tier(tier)
def main(self, **kwargs):
- Runner.update_config_file()
-
if 'noclean' in kwargs:
self.clean_flag = not kwargs['noclean']
if 'report' in kwargs:
from functest.utils.constants import CONST
+import six
+
class Env(object):
msg = prettytable.PrettyTable(
header_style='upper', padding_width=5,
field_names=['Functest Environment', 'value'])
- for key, value in env_info.iteritems():
+ for key, value in six.iteritems(env_info):
if key is not None:
msg.add_row([key, value])
click.echo(msg.get_string())
import os
-from urlparse import urlparse
import click
+import six
+from six.moves.urllib.parse import urlparse
from functest.ci import check_deployment
from functest.utils.constants import CONST
def snapshot_create(self):
self.ping_endpoint()
if os.path.isfile(self.snapshot_file):
- answer = raw_input("It seems there is already an OpenStack "
- "snapshot. Do you want to overwrite it with "
- "the current OpenStack status? [y|n]\n")
+ answer = six.moves.input(
+ "It seems there is already an OpenStack "
+ "snapshot. Do you want to overwrite it with "
+ "the current OpenStack status? [y|n]\n")
while True:
if answer.lower() in ["y", "yes"]:
break
elif answer.lower() in ["n", "no"]:
return
else:
- answer = raw_input("Invalid answer. Please type [y|n]\n")
+ answer = six.moves.input(
+ "Invalid answer. Please type [y|n]\n")
click.echo("Generating Openstack snapshot...")
os_snapshot.main()
import json
import logging
-import urllib
from functools import wraps
import requests
+from six.moves import urllib
from functest.utils.constants import CONST
import functest.utils.functest_utils as ft_utils
assert environment
uri_comp = "/recorders/environment/"
- uri_comp += urllib.quote_plus(environment)
+ uri_comp += urllib.parse.quote_plus(environment)
# Creds
creds_usr = ft_utils.get_functest_config(
except Exception as exc: # pylint: disable=broad-except
EnergyRecorder.logger.info(
"Energy recorder API is not available, cause=%s",
- exc.message)
+ str(exc))
api_available = False
# Final config
EnergyRecorder.energy_recorder_api = {
FLAVOR_NAME = CONST.__getattribute__('rally_flavor_name')
FLAVOR_ALT_NAME = CONST.__getattribute__('rally_flavor_alt_name')
FLAVOR_EXTRA_SPECS = None
+ FLAVOR_RAM = 512
+ FLAVOR_RAM_ALT = 1024
if hasattr(CONST, 'flavor_extra_specs'):
FLAVOR_EXTRA_SPECS = CONST.__getattribute__('flavor_extra_specs')
+ FLAVOR_RAM = 1024
+ FLAVOR_RAM_ALT = 2048
RALLY_DIR = pkg_resources.resource_filename(
'functest', 'opnfv_tests/openstack/rally')
LOGGER.debug("Creating flavor '%s'...", self.flavor_name)
flavor_creator = OpenStackFlavor(
self.os_creds, FlavorConfig(
- name=self.flavor_name, ram=512, disk=1, vcpus=1,
+ name=self.flavor_name, ram=self.FLAVOR_RAM, disk=1, vcpus=1,
metadata=self.FLAVOR_EXTRA_SPECS))
if flavor_creator is None or flavor_creator.create() is None:
raise Exception("Failed to create flavor")
LOGGER.debug("Creating flavor '%s'...", self.flavor_alt_name)
flavor_alt_creator = OpenStackFlavor(
self.os_creds, FlavorConfig(
- name=self.flavor_alt_name, ram=1024, disk=1, vcpus=1,
- metadata=self.FLAVOR_EXTRA_SPECS))
+ name=self.flavor_alt_name, ram=self.FLAVOR_RAM_ALT, disk=1,
+ vcpus=1, metadata=self.FLAVOR_EXTRA_SPECS))
if flavor_alt_creator is None or flavor_alt_creator.create() is None:
raise Exception("Failed to create flavor")
self.creators.append(flavor_alt_creator)
flavor_metadata_alt = None
if 'ovs' in scenario or 'fdio' in scenario:
flavor_metadata_alt = create_flavor.MEM_PAGE_SIZE_LARGE
+ CONST.__setattr__('openstack_flavor_ram', 1024)
flavor_creator_alt = OpenStackFlavor(
self.os_creds, FlavorConfig(
name=CONST.__getattribute__(
"Creating flavor with name: '%s'", self.flavor_name)
scenario = CONST.__getattribute__('DEPLOY_SCENARIO')
flavor_metadata = None
+ flavor_ram = 512
if 'ovs' in scenario or 'fdio' in scenario:
flavor_metadata = create_flavor.MEM_PAGE_SIZE_LARGE
+ flavor_ram = 1024
flavor_creator = OpenStackFlavor(
self.os_creds,
- FlavorConfig(name=self.flavor_name, ram=512, disk=1, vcpus=1,
- metadata=flavor_metadata))
+ FlavorConfig(name=self.flavor_name, ram=flavor_ram, disk=1,
+ vcpus=1, metadata=flavor_metadata))
flavor_creator.create()
self.creators.append(flavor_creator)
self.run_tests_parser = run_tests.RunTestsParser()
- self.config_file_yaml = {'general': {
- 'openstack': {
- 'image_name': 'test_image_name'}},
- 'results': {
- 'test_db_url': 'url1'}}
- self.config_file_patch_yaml = {'fdio': {'general': {
- 'openstack': {
- 'image_name':
- 'test_image_name_2'}}}}
- self.config_file_aarcg64_patch_yaml = {'os': {'general': {
- 'openstack': {'image_name': 'test_image_name_3'}}}}
-
- @mock.patch('functest.ci.run_tests.Runner.patch_file')
- def test_update_config_file_default(self, mock_patch):
- self.runner.update_config_file()
- mock_patch.assert_called()
-
- def test_patch_file_missing_file(self):
- patch_file_path = "unexisting_file"
- with self.assertRaises(IOError):
- self.runner.patch_file(patch_file_path)
-
- @mock.patch('functest.ci.run_tests.ft_utils.merge_dicts')
- @mock.patch('functest.ci.run_tests.ft_utils.get_functest_yaml')
- def test_patch_file_default(self, *mock_methods):
- CONST.__setattr__('DEPLOY_SCENARIO', 'os-nosdn-nofeature-noha')
- with mock.patch(
- 'six.moves.builtins.open', mock.mock_open()), mock.patch(
- 'functest.ci.run_tests.yaml.safe_load') as yaml1, mock.patch(
- 'functest.ci.run_tests.ft_utils.get_functest_yaml') as yaml2:
- yaml1.return_value = self.config_file_patch_yaml
- yaml2.return_value = self.config_file_yaml
- self.runner.patch_file(yaml1)
- mock_methods[1].assert_not_called()
- mock_methods[0].assert_not_called()
-
- @mock.patch('functest.ci.run_tests.ft_utils.merge_dicts')
- @mock.patch('functest.ci.run_tests.os.remove')
- def test_patch_file_match_scenario(self, *mock_methods):
- CONST.__setattr__('DEPLOY_SCENARIO', 'os-nosdn-fdio-noha')
- with mock.patch(
- 'six.moves.builtins.open', mock.mock_open()), mock.patch(
- 'functest.ci.run_tests.yaml.safe_load') as yaml1, mock.patch(
- 'functest.ci.run_tests.ft_utils.get_functest_yaml') as yaml2:
- yaml1.return_value = self.config_file_patch_yaml
- yaml2.return_value = self.config_file_yaml
- self.runner.patch_file(yaml2)
- mock_methods[1].assert_called()
- mock_methods[0].assert_called()
-
@mock.patch('functest.ci.run_tests.logger.error')
def test_source_rc_file_missing_file(self, mock_logger_error):
with mock.patch('functest.ci.run_tests.os.path.isfile',
return_value=True)
@mock.patch('functest.cli.commands.cli_os.click.echo')
def test_snapshot_create_overwrite(self, mock_click_echo, mock_os_path):
- with mock.patch('__builtin__.raw_input', return_value="y") \
+ with mock.patch('six.moves.input', return_value="y") \
as mock_raw_input, \
mock.patch.object(self.cli_os, 'ping_endpoint'), \
mock.patch('functest.cli.commands.cli_os.os_snapshot.main') \
return_value=True)
@mock.patch('functest.cli.commands.cli_os.click.echo')
def test_snapshot_show_default(self, mock_click_echo, mock_os_path):
- with mock.patch('__builtin__.open', mock.mock_open(read_data='0')) \
+ with mock.patch('six.moves.builtins.open',
+ mock.mock_open(read_data='0')) \
as m:
self.cli_os.snapshot_file = self.snapshot_file
self.cli_os.snapshot_show()
"""Unitary test for energy module."""
# pylint: disable=unused-argument
import logging
+import requests
import unittest
import mock
'{"message": "An unhandled API exception occurred (MOCK)"}',
500
)
+RECORDER_NOT_FOUND = MockHttpResponse(
+ '{"message": "Recorder not found (MOCK)"}',
+ 404
+)
def config_loader_mock(config_key):
return "user"
elif config_key == "energy_recorder.api_password":
return "password"
- else:
- raise Exception("Config not mocked")
def config_loader_mock_no_creds(config_key):
return ""
elif config_key == "energy_recorder.api_password":
return ""
- else:
- raise Exception("Config not mocked:" + config_key)
+# pylint: disable=too-many-public-methods
class EnergyRecorderTest(unittest.TestCase):
"""Energy module unitary test suite."""
timeout=EnergyRecorder.CONNECTION_TIMEOUT
)
+ @mock.patch('functest.energy.energy.EnergyRecorder.load_config',
+ side_effect=Exception("Internal execution error (MOCK)"))
+ def test_start_exception(self, conf_loader_mock=None):
+ """EnergyRecorder.start test with exception during execution."""
+ start_status = EnergyRecorder.start(CASE_NAME)
+ self.assertFalse(start_status)
+
@mock.patch('functest.energy.energy.requests.post',
return_value=RECORDER_KO)
def test_start_api_error(self, post_mock=None):
timeout=EnergyRecorder.CONNECTION_TIMEOUT
)
+ @mock.patch('functest.energy.energy.EnergyRecorder.load_config',
+ side_effect=requests.exceptions.ConnectionError())
+ def test_set_step_connection_error(self, conf_loader_mock=None):
+ """EnergyRecorder.start test with exception during execution."""
+ step_status = EnergyRecorder.set_step(STEP_NAME)
+ self.assertFalse(step_status)
+
@mock.patch('functest.energy.energy.requests.delete',
return_value=RECORDER_OK)
def test_stop(self, delete_mock=None):
with self.assertRaises(Exception) as context:
self.__decorated_method_with_ex()
self.assertTrue(
- self.exception_message_to_preserve in context.exception
+ self.exception_message_to_preserve in str(context.exception)
)
self.assertTrue(finish_mock.called)
scenario = EnergyRecorder.get_current_scenario()
self.assertTrue(scenario is not None)
+ @mock.patch('functest.energy.energy.requests.get',
+ return_value=RECORDER_NOT_FOUND)
+ def test_current_scenario_not_found(self, get_mock=None):
+ """Test get current scenario not existing."""
+ CONST.__setattr__('NODE_NAME', 'MOCK_POD')
+ self.test_load_config()
+ scenario = EnergyRecorder.get_current_scenario()
+ self.assertTrue(scenario is None)
+
+ @mock.patch('functest.energy.energy.requests.get',
+ return_value=RECORDER_KO)
+ def test_current_scenario_api_error(self, get_mock=None):
+ """Test get current scenario with API error."""
+ CONST.__setattr__('NODE_NAME', 'MOCK_POD')
+ self.test_load_config()
+ scenario = EnergyRecorder.get_current_scenario()
+ self.assertTrue(scenario is None)
+
+ @mock.patch('functest.energy.energy.EnergyRecorder.load_config',
+ side_effect=Exception("Internal execution error (MOCK)"))
+ def test_current_scenario_exception(self, get_mock=None):
+ """Test get current scenario with exception."""
+ scenario = EnergyRecorder.get_current_scenario()
+ self.assertTrue(scenario is None)
if __name__ == "__main__":
logging.disable(logging.CRITICAL)
import re
-class RegexMatch(str):
+class RegexMatch(object):
+ def __init__(self, msg):
+ self.msg = msg
+
def __eq__(self, other):
- match = re.search(self, other)
+ match = re.search(self.msg, other)
if match:
return True
return False
-class SubstrMatch(str):
+class SubstrMatch(object):
+ def __init__(self, msg):
+ self.msg = msg
+
def __eq__(self, other):
- if self in other:
+ if self.msg in other:
return True
return False
"-----------------"
"---------")
+ @mock.patch('time.sleep')
@mock.patch('functest.utils.openstack_clean.logger.debug')
- def test_remove_instances(self, mock_logger_debug):
+ def test_remove_instances(self, mock_logger_debug, *args):
with mock.patch('functest.utils.openstack_clean.os_utils'
'.get_instances', return_value=self.test_list):
openstack_clean.remove_instances(self.client, self.update_list)
"instance and will "
"NOT be deleted.")
+ @mock.patch('time.sleep')
@mock.patch('functest.utils.openstack_clean.logger.debug')
- def test_remove_instances_missing_instances(self, mock_logger_debug):
+ def test_remove_instances_missing_instances(self, mock_logger_debug,
+ *args):
with mock.patch('functest.utils.openstack_clean.os_utils'
'.get_instances', return_value=[]):
openstack_clean.remove_instances(self.client, self.update_list)
mock_logger_debug.assert_any_call("Removing Nova instances...")
mock_logger_debug.assert_any_call("No instances found.")
+ @mock.patch('time.sleep')
@mock.patch('functest.utils.openstack_clean.logger.debug')
- def test_remove_instances_delete_success(self, mock_logger_debug):
+ def test_remove_instances_delete_success(self, mock_logger_debug, *args):
with mock.patch('functest.utils.openstack_clean.os_utils'
'.get_instances', return_value=self.test_list), \
mock.patch('functest.utils.openstack_clean.os_utils'
" '\s*\S+'"
" ..."))
+ @mock.patch('time.sleep')
@mock.patch('functest.utils.openstack_clean.logger.debug')
- def test_remove_instances_pending_delete_success(self, mock_logger_debug):
+ def test_remove_instances_pending_delete_success(self, mock_logger_debug,
+ *args):
with mock.patch('functest.utils.openstack_clean.os_utils'
'.get_instances', return_value=self.deleted_list), \
mock.patch('functest.utils.openstack_clean.os_utils'
" '\s*\S+'"
" ...").assert_not_called()
+ @mock.patch('time.sleep')
@mock.patch('functest.utils.openstack_clean.logger.debug')
- def test_remove_instances_other_delete_success(self, mock_logger_debug):
+ def test_remove_instances_other_delete_success(self, mock_logger_debug,
+ *args):
with mock.patch('functest.utils.openstack_clean.os_utils'
'.get_instances', return_value=self.other_list), \
mock.patch('functest.utils.openstack_clean.os_utils'
" '\s*\S+'"
" ..."))
+ @mock.patch('time.sleep')
@mock.patch('functest.utils.openstack_clean.logger.error')
@mock.patch('functest.utils.openstack_clean.logger.debug')
def test_remove_instances_delete_failed(self, mock_logger_debug,
- mock_logger_error):
+ mock_logger_error, *args):
with mock.patch('functest.utils.openstack_clean.os_utils'
'.get_instances', return_value=self.test_list), \
mock.patch('functest.utils.openstack_clean.os_utils'
def test_remove_floatingips_delete_success(self, mock_logger_debug):
with mock.patch('functest.utils.openstack_clean.os_utils'
'.get_floating_ips',
- return_value=self.floatingips_list), \
+ side_effect=[self.floatingips_list, None]), \
mock.patch('functest.utils.openstack_clean.os_utils'
'.delete_floating_ip', return_value=True):
openstack_clean.remove_floatingips(self.client, self.remove_list)
RegexMatch("Removing floating "
"IP \s*\S+ ..."))
+ @mock.patch('time.sleep')
@mock.patch('functest.utils.openstack_clean.remove_routers')
@mock.patch('functest.utils.openstack_clean.remove_ports')
@mock.patch('functest.utils.openstack_clean.logger.debug')
def test_remove_networks(self, mock_logger_debug,
mock_remove_ports,
- mock_remove_routers):
+ mock_remove_routers, *args):
with mock.patch('functest.utils.openstack_clean.os_utils'
'.get_network_list',
return_value=self.test_dict_list), \
self.routers,
self.update_list)
+ @mock.patch('time.sleep')
@mock.patch('functest.utils.openstack_clean.remove_routers')
@mock.patch('functest.utils.openstack_clean.remove_ports')
@mock.patch('functest.utils.openstack_clean.logger.debug')
def test_remove_networks_missing_networks(self, mock_logger_debug,
mock_remove_ports,
- mock_remove_routers):
+ mock_remove_routers, *args):
with mock.patch('functest.utils.openstack_clean.os_utils'
'.get_network_list', return_value=None), \
mock.patch('functest.utils.openstack_clean.os_utils'
self.routers,
self.update_list)
+ @mock.patch('time.sleep')
@mock.patch('functest.utils.openstack_clean.remove_routers')
@mock.patch('functest.utils.openstack_clean.remove_ports')
@mock.patch('functest.utils.openstack_clean.logger.debug')
def test_remove_networks_delete_success(self, mock_logger_debug,
mock_remove_ports,
- mock_remove_routers):
+ mock_remove_routers, *args):
with mock.patch('functest.utils.openstack_clean.os_utils'
'.get_network_list',
self.routers,
self.remove_list)
+ @mock.patch('time.sleep')
@mock.patch('functest.utils.openstack_clean.remove_routers')
@mock.patch('functest.utils.openstack_clean.remove_ports')
@mock.patch('functest.utils.openstack_clean.logger.error')
def test_remove_networks_delete_failed(self, mock_logger_debug,
mock_logger_error,
mock_remove_ports,
- mock_remove_routers):
+ mock_remove_routers, *args):
with mock.patch('functest.utils.openstack_clean.os_utils'
'.get_network_list',
return_value=self.test_dict_list), \
as mock_remove_tenants, \
mock.patch('functest.utils.openstack_clean.yaml.safe_load',
return_value=mock.Mock()), \
- mock.patch('__builtin__.open', mock.mock_open()) as m:
+ mock.patch('six.moves.builtins.open', mock.mock_open()) as m:
openstack_clean.main()
self.assertTrue(mock_remove_instances)
self.assertTrue(mock_remove_images)
return_value=self.update_list), \
mock.patch('functest.utils.openstack_snapshot.get_tenants',
return_value=self.update_list), \
- mock.patch('__builtin__.open', mock.mock_open()) as m:
+ mock.patch('six.moves.builtins.open', mock.mock_open()) as m:
openstack_snapshot.main()
mock_logger_info.assert_called_once_with("Generating OpenStack "
"snapshot...")
except:
pass
f = 'rc_file'
- with mock.patch('__builtin__.open', mock.mock_open(read_data=msg),
+ with mock.patch('six.moves.builtins.open',
+ mock.mock_open(read_data=msg),
create=True) as m:
m.return_value.__iter__ = lambda self: iter(self.readline, '')
openstack_utils.source_credentials(f)
return_value=True), \
mock.patch('functest.utils.openstack_utils.get_image_id',
return_value=''), \
- mock.patch('__builtin__.open',
+ mock.patch('six.moves.builtins.open',
mock.mock_open(read_data='1')) as m:
self.assertEqual(openstack_utils.
create_glance_image(self.glance_client,
#!/usr/bin/env python
+# pylint: disable=missing-docstring
+
+import os
+import pkg_resources
import yaml
import six
-from functest.utils import env
-
class Config(object):
def __init__(self):
try:
- with open(env.ENV.CONFIG_FUNCTEST_YAML) as f:
- self.functest_yaml = yaml.safe_load(f)
- self._parse(None, self.functest_yaml)
+ with open(pkg_resources.resource_filename(
+ 'functest', 'ci/config_functest.yaml')) as yfile:
+ self.functest_yaml = yaml.safe_load(yfile)
except Exception as error:
raise Exception('Parse config failed: {}'.format(str(error)))
+ @staticmethod
+ def _merge_dicts(dict1, dict2):
+ for k in set(dict1.keys()).union(dict2.keys()):
+ if k in dict1 and k in dict2:
+ if isinstance(dict1[k], dict) and isinstance(dict2[k], dict):
+ yield (k, dict(Config._merge_dicts(dict1[k], dict2[k])))
+ else:
+ yield (k, dict2[k])
+ elif k in dict1:
+ yield (k, dict1[k])
+ else:
+ yield (k, dict2[k])
+
+ def patch_file(self, patch_file_path):
+ with open(patch_file_path) as yfile:
+ patch_file = yaml.safe_load(yfile)
+
+ for key in patch_file:
+ if key in os.environ.get('DEPLOY_SCENARIO', ""):
+ self.functest_yaml = dict(Config._merge_dicts(
+ self.functest_yaml, patch_file[key]))
+
def _parse(self, attr_now, left_parametes):
for param_n, param_v in six.iteritems(left_parametes):
attr_further = self._get_attr_further(attr_now, param_n)
if isinstance(param_v, dict):
self._parse(attr_further, param_v)
- def _get_attr_further(self, attr_now, next):
+ @staticmethod
+ def _get_attr_further(attr_now, next): # pylint: disable=redefined-builtin
return attr_now if next == 'general' else (
'{}_{}'.format(attr_now, next) if attr_now else next)
+ def fill(self):
+ try:
+ self._parse(None, self.functest_yaml)
+ except Exception as error:
+ raise Exception('Parse config failed: {}'.format(str(error)))
+
CONF = Config()
+CONF.patch_file(pkg_resources.resource_filename(
+ 'functest', 'ci/config_patch.yaml'))
+if os.getenv("POD_ARCH", None) and os.getenv("POD_ARCH", None) in ['aarch64']:
+ CONF.patch_file(pkg_resources.resource_filename(
+ 'functest', 'ci/config_aarch64_patch.yaml'))
+CONF.fill()
return get_parameter_from_yaml(parameter, yaml_)
-def merge_dicts(dict1, dict2):
- for k in set(dict1.keys()).union(dict2.keys()):
- if k in dict1 and k in dict2:
- if isinstance(dict1[k], dict) and isinstance(dict2[k], dict):
- yield (k, dict(merge_dicts(dict1[k], dict2[k])))
- else:
- yield (k, dict2[k])
- elif k in dict1:
- yield (k, dict1[k])
- else:
- yield (k, dict2[k])
-
-
def get_functest_yaml():
with open(constants.CONST.__getattribute__('CONFIG_FUNCTEST_YAML')) as f:
functest_yaml = yaml.safe_load(f)
finally:
endwin()
- print '\nSnake.PY-26lines by Kris Cieslak (defaultset.blogspot.com).'
- print 'OPNFV adaptation by Functest dream team.'
+ print('\nSnake.PY-26ines by Kris Cieslak (defaultset.blogspot.com).')
+ print('OPNFV adaptation by Functest dream team.')
score = str(len(snake) - len(body) - 1)
print ('Thanks for playing, your score: %s.' % score)
- print 'Find and fix more bugs in your real OPNFV setup!\n'
+ print('Find and fix more bugs in your real OPNFV setup!\n')
modules =
functest.api
functest.core
+ functest.energy
functest.opnfv_tests.sdn.odl
functest.tests.unit.core
+ functest.tests.unit.energy
functest.tests.unit.odl
functest.tests.unit.utils.test_decorators
functest.utils.decorators
basepython = python2.7
files =
docker
+ functest/api
functest/ci
functest/opnfv_tests/vnf
commands =
yamllint {[testenv:yamllint]files}
- - yamllint functest/api
[testenv:py35]
dirs =
functest/tests/unit/ci
+ functest/tests/unit/cli
functest/tests/unit/core
+ functest/tests/unit/energy
functest/tests/unit/odl
- functest/tests/unit/utils/test_decorators.py
+ functest/tests/unit/utils
commands = nosetests {[testenv:py35]dirs}
[testenv:cover]
basepython = python2.7
dirs =
functest/tests/unit/core
+ functest/tests/unit/energy
functest/tests/unit/odl
functest/tests/unit/utils/test_decorators.py
commands = nosetests --with-coverage --cover-tests \
--cover-package functest.core \
+ --cover-package functest.energy \
--cover-package functest.opnfv_tests.sdn.odl \
--cover-package functest.tests.unit \
--cover-package functest.utils.decorators \