diff options
-rw-r--r-- | docker/vnf/Dockerfile | 11 | ||||
-rw-r--r-- | docs/testing/user/userguide/test_details.rst | 33 | ||||
-rw-r--r-- | docs/testing/user/userguide/test_overview.rst | 11 | ||||
-rw-r--r-- | functest/ci/config_aarch64_patch.yaml | 8 | ||||
-rw-r--r-- | functest/ci/download_images.sh | 4 | ||||
-rw-r--r-- | functest/ci/rally_aarch64_patch.conf | 2 | ||||
-rw-r--r-- | functest/opnfv_tests/openstack/rally/rally.py | 142 | ||||
-rw-r--r-- | functest/opnfv_tests/openstack/tempest/tempest.py | 3 | ||||
-rw-r--r-- | functest/opnfv_tests/openstack/vping/vping_base.py | 5 | ||||
-rw-r--r-- | functest/opnfv_tests/sdn/odl/odl.py | 12 | ||||
-rw-r--r-- | functest/opnfv_tests/vnf/epc/juju_epc.py | 103 | ||||
-rw-r--r-- | functest/opnfv_tests/vnf/ims/cloudify_ims.py | 169 | ||||
-rw-r--r-- | functest/opnfv_tests/vnf/ims/cloudify_ims.yaml | 10 | ||||
-rw-r--r-- | functest/opnfv_tests/vnf/ims/cloudify_ims_perf.yaml | 4 | ||||
-rw-r--r-- | functest/opnfv_tests/vnf/router/cloudify_vrouter.py | 179 | ||||
-rw-r--r-- | functest/opnfv_tests/vnf/router/cloudify_vrouter.yaml | 11 | ||||
-rw-r--r-- | functest/tests/unit/odl/test_odl.py | 148 | ||||
-rw-r--r-- | functest/tests/unit/openstack/rally/test_rally.py | 65 |
18 files changed, 580 insertions, 340 deletions
diff --git a/docker/vnf/Dockerfile b/docker/vnf/Dockerfile index afaec2320..54241875e 100644 --- a/docker/vnf/Dockerfile +++ b/docker/vnf/Dockerfile @@ -2,7 +2,9 @@ FROM opnfv/functest-core ARG BRANCH=master ARG OPENSTACK_TAG=stable/queens -ARG VIMS_TAG=stable +ARG VIMS_TEST_TAG=stable +ARG VIMS_TAG=fraser +ARG VROUTER_TAG=fraser ARG JUJU_TAG=tags/juju-2.2.5 ENV GOPATH /src/epc-requirements/go @@ -17,7 +19,9 @@ RUN apk --no-cache add --update \ wget -q -O- https://git.openstack.org/cgit/openstack/requirements/plain/upper-constraints.txt?h=$OPENSTACK_TAG | \ sed -E s/^tempest==+\(.*\)$/-e\ git+https:\\/\\/github.com\\/openstack\\/tempest@\\1#egg=tempest/ | \ > upper-constraints.txt && \ - git clone --depth 1 -b $VIMS_TAG https://github.com/boucherv-orange/clearwater-live-test /src/vims-test && \ + git clone --depth 1 -b $VIMS_TEST_TAG https://github.com/boucherv-orange/clearwater-live-test.git /src/vims-test && \ + git clone --depth 1 -b $VIMS_TAG https://github.com/Orange-OpenSource/opnfv-cloudify-clearwater.git /src/vims && \ + git clone --depth 1 -b $VROUTER_TAG https://github.com/oolorg/opnfv-vnf-vyos-blueprint.git /src/opnfv-vnf-vyos-blueprint && \ git clone https://github.com/RebacaInc/abot_charm.git /src/epc-requirements/abot_charm && \ python3 -m pip install --no-cache-dir --src /src -cupper-constraints.txt \ -chttps://git.opnfv.org/functest/plain/upper-constraints.txt?h=$BRANCH \ @@ -28,7 +32,8 @@ RUN apk --no-cache add --update \ go install -v github.com/juju/juju/... && \ rm -rf $GOPATH/go/src/ $GOPATH/pkg && \ (cd /src/vims-test && bundle config build.nokogiri --use-system-libraries && bundle install --system) && \ - rm -r upper-constraints.txt /src/vims-test/.git /src/epc-requirements/abot_charm/.git && \ + rm -r upper-constraints.txt /src/vims-test/.git /src/vims/.git /src/opnfv-vnf-vyos-blueprint/.git \ + /src/epc-requirements/abot_charm/.git && \ apk del .build-deps COPY testcases.yaml /usr/lib/python2.7/site-packages/xtesting/ci/testcases.yaml CMD ["run_tests", "-t", "all"] diff --git a/docs/testing/user/userguide/test_details.rst b/docs/testing/user/userguide/test_details.rst index 543f66a19..38d35a697 100644 --- a/docs/testing/user/userguide/test_details.rst +++ b/docs/testing/user/userguide/test_details.rst @@ -422,13 +422,41 @@ The vyos-vrouter architecture is described in `[14]`_ juju_epc ^^^^^^^^ +The Evolved Packet Core (EPC) is the main component of the System Architecture +Evolution (SAE) which forms the core of the 3GPP LTE specification. +vEPC has been integrated in Functest to demonstrate the capability to deploy a +complex mobility-specific NFV scenario on the OPNFV platform. The OAI EPC +supports most of the essential functions defined by the 3GPP Technical Specs; +hence the successful execution of functional tests on the OAI EPC provides a +good endorsement of the underlying NFV platform. + +This integration also includes ABot, a Test Orchestration system that enables +test scenarios to be defined in high-level DSL. ABot is also deployed as a +VM on the OPNFV platform; and this provides an example of the automation +driver and the Test VNF being both deployed as separate VNFs on the underlying +OPNFV platform. + +The Workflow is as follows: + * Deploy Orchestrator + Deploy Juju controller using Bootstrap command. + * Deploy VNF + Deploy ABot orchestrator and OAI EPC as Juju charms. + Configuration of ABot and OAI EPC components is handled through + built-in Juju relations. + * Test VNF + Execution of ABot feature files triggered by Juju actions. + This executes a suite of LTE signalling tests on the OAI EPC. + * Reporting + ABot test results are parsed accordingly and pushed to Functest Db. + +Details of the ABot test orchestration tool may be found in `[15]`_ Kubernetes (K8s) ---------------- Kubernetes testing relies on sets of tests, which are part of the Kubernetes -source tree, such as the Kubernetes End-to-End (e2e) tests `[15]`_. +source tree, such as the Kubernetes End-to-End (e2e) tests `[16]`_. The kubernetes testcases are distributed across various Tiers: @@ -460,4 +488,5 @@ The kubernetes testcases are distributed across various Tiers: .. _`[12]`: http://docs.opnfv.org/en/latest/submodules/functest/docs/testing/user/userguide/index.html .. _`[13]`: https://wiki.opnfv.org/display/PROJ/SNAPS-OO .. _`[14]`: https://github.com/oolorg/opnfv-functest-vrouter -.. _`[15]`: https://github.com/kubernetes/community/blob/master/contributors/devel/e2e-tests.md +.. _`[15]`: https://www.rebaca.com/abot-test-orchestration-tool/ +.. _`[16]`: https://github.com/kubernetes/community/blob/master/contributors/devel/e2e-tests.md diff --git a/docs/testing/user/userguide/test_overview.rst b/docs/testing/user/userguide/test_overview.rst index 4644109a5..b88a99caf 100644 --- a/docs/testing/user/userguide/test_overview.rst +++ b/docs/testing/user/userguide/test_overview.rst @@ -147,8 +147,15 @@ validate the scenario for the release. | | | vyos | vRouter testing | | | | \_vrouter | | | | +------------+----------------------------------+ -| | | juju_epc | vEPC validation with Juju as VNF | -| | | | manager and ABoT as test executor| +| | | juju_epc | Validates deployment of a complex| +| | | | mobility VNF on OPNFV Platform. | +| | | | Uses Juju for deploying the OAI | +| | | | EPC and ABot for defining test | +| | | | scenarios using high-level DSL. | +| | | | VNF tests reference 3GPP | +| | | | Technical Specs and are executed | +| | | | through protocol drivers provided| +| | | | by ABot. | | | +------------+----------------------------------+ | | | cloudify | Based on cloudify_ims test case | | | | \_ims_perf | cloudify_ims_perf substitutes | diff --git a/functest/ci/config_aarch64_patch.yaml b/functest/ci/config_aarch64_patch.yaml index 2f1289c1c..983461d78 100644 --- a/functest/ci/config_aarch64_patch.yaml +++ b/functest/ci/config_aarch64_patch.yaml @@ -3,8 +3,10 @@ os: general: openstack: image_name: TestVM - image_file_name: cirros-d161201-aarch64-disk.img + image_file_name: cirros-0.4.0-aarch64-disk.img image_password: gocubsgo + image_url: + /home/opnfv/functest/images/cirros-0.4.0-aarch64-disk.img extra_properties: hw_firmware_type: 'uefi' hw_video_model: 'vga' @@ -15,7 +17,7 @@ os: images: glance_tests: disk_file: - /home/opnfv/functest/images/cirros-d161201-aarch64-disk.img + /home/opnfv/functest/images/cirros-0.4.0-aarch64-disk.img extra_properties: hw_firmware_type: 'uefi' short_id: 'ubuntu16.04' @@ -24,7 +26,7 @@ os: hw_scsi_model: 'virtio-scsi' cirros: disk_file: - /home/opnfv/functest/images/cirros-d161201-aarch64-disk.img + /home/opnfv/functest/images/cirros-0.4.0-aarch64-disk.img extra_properties: hw_firmware_type: 'uefi' short_id: 'ubuntu16.04' diff --git a/functest/ci/download_images.sh b/functest/ci/download_images.sh index c498b9bcc..d3dcee266 100644 --- a/functest/ci/download_images.sh +++ b/functest/ci/download_images.sh @@ -11,9 +11,7 @@ https://cloud.centos.org/centos/7/images/CentOS-7-x86_64-GenericCloud.qcow2 https://cloud-images.ubuntu.com/releases/16.04/release/ubuntu-16.04-server-cloudimg-amd64-disk1.img http://repository.cloudifysource.org/cloudify/4.0.1/sp-release/cloudify-manager-premium-4.0.1.qcow2 http://download.cirros-cloud.net/0.4.0/cirros-0.4.0-x86_64-lxc.tar.gz -http://download.cirros-cloud.net/daily/20161201/cirros-d161201-aarch64-disk.img -http://download.cirros-cloud.net/daily/20161201/cirros-d161201-aarch64-initramfs -http://download.cirros-cloud.net/daily/20161201/cirros-d161201-aarch64-kernel +http://download.cirros-cloud.net/0.4.0/cirros-0.4.0-aarch64-disk.img https://cloud-images.ubuntu.com/releases/14.04/release/ubuntu-14.04-server-cloudimg-arm64-uefi1.img http://cloud.centos.org/altarch/7/images/aarch64/CentOS-7-aarch64-GenericCloud.qcow2.xz https://sourceforge.net/projects/ool-opnfv/files/vyos-1.1.7.img diff --git a/functest/ci/rally_aarch64_patch.conf b/functest/ci/rally_aarch64_patch.conf index e5cae8137..baeceac76 100644 --- a/functest/ci/rally_aarch64_patch.conf +++ b/functest/ci/rally_aarch64_patch.conf @@ -1,5 +1,5 @@ img_name_regex = ^TestVM$ -img_url = http://download.cirros-cloud.net/daily/20161201/cirros-d161201-aarch64-disk.img +img_url = http://download.cirros-cloud.net/0.4.0/cirros-0.4.0-aarch64-disk.img flavor_ref_ram = 256 flavor_ref_alt_ram = 256 heat_instance_type_ram = 256 diff --git a/functest/opnfv_tests/openstack/rally/rally.py b/functest/opnfv_tests/openstack/rally/rally.py index 8d1bfabb5..cca198853 100644 --- a/functest/opnfv_tests/openstack/rally/rally.py +++ b/functest/opnfv_tests/openstack/rally/rally.py @@ -47,7 +47,7 @@ class RallyBase(testcase.TestCase): config.CONF, 'dir_functest_images'), GLANCE_IMAGE_FILENAME) GLANCE_IMAGE_FORMAT = getattr(config.CONF, 'openstack_image_disk_format') GLANCE_IMAGE_EXTRA_PROPERTIES = getattr( - config.CONF, 'image_properties', {}) + config.CONF, 'openstack_extra_properties', {}) FLAVOR_NAME = getattr(config.CONF, 'rally_flavor_name') FLAVOR_ALT_NAME = getattr(config.CONF, 'rally_flavor_alt_name') FLAVOR_RAM = 512 @@ -181,14 +181,14 @@ class RallyBase(testcase.TestCase): :return: Bool """ rally_report = json.loads(json_raw) - for report in rally_report: - if report is None or report.get('result') is None: - return False - - for result in report.get('result'): - if result is None or result.get('error'): + tasks = rally_report.get('tasks') + if tasks: + for task in tasks: + if task.get('status') != 'finished' or \ + task.get('pass_sla') is not True: return False - + else: + return False return True def _migration_supported(self): @@ -316,6 +316,52 @@ class RallyBase(testcase.TestCase): return True + def _save_results(self, test_name, task_id): + """ Generate and save task execution results""" + # check for result directory and create it otherwise + if not os.path.exists(self.RESULTS_DIR): + LOGGER.debug('%s does not exist, we create it.', + self.RESULTS_DIR) + os.makedirs(self.RESULTS_DIR) + + # put detailed result to log + cmd = (["rally", "task", "detailed", "--uuid", task_id]) + LOGGER.debug('running command: %s', cmd) + proc = subprocess.Popen(cmd, stdout=subprocess.PIPE, + stderr=subprocess.STDOUT) + json_detailed = self.get_cmd_output(proc) + LOGGER.info('%s', json_detailed) + + # save report as JSON + cmd = (["rally", "task", "report", "--json", "--uuid", task_id]) + LOGGER.debug('running command: %s', cmd) + with open(os.devnull, 'w') as devnull: + proc = subprocess.Popen(cmd, stdout=subprocess.PIPE, + stderr=devnull) + json_results = self.get_cmd_output(proc) + report_json_name = 'opnfv-{}.json'.format(test_name) + report_json_dir = os.path.join(self.RESULTS_DIR, report_json_name) + with open(report_json_dir, 'w') as r_file: + LOGGER.debug('saving json file') + r_file.write(json_results) + + # save report as HTML + report_html_name = 'opnfv-{}.html'.format(test_name) + report_html_dir = os.path.join(self.RESULTS_DIR, report_html_name) + cmd = (["rally", "task", "report", "--html", "--uuid", task_id, + "--out", report_html_dir]) + LOGGER.debug('running command: %s', cmd) + with open(os.devnull, 'w') as devnull: + subprocess.Popen(cmd, stdout=subprocess.PIPE, stderr=devnull) + + self._append_summary(json_results, test_name) + + # parse JSON operation result + if self.task_succeed(json_results): + LOGGER.info('Test scenario: "{}" OK.'.format(test_name) + "\n") + else: + LOGGER.info('Test scenario: "{}" Failed.'.format(test_name) + "\n") + def _run_task(self, test_name): """Run a task.""" LOGGER.info('Starting test scenario "%s" ...', test_name) @@ -351,47 +397,9 @@ class RallyBase(testcase.TestCase): stderr=subprocess.STDOUT) output = self.get_cmd_output(proc) LOGGER.error("Task validation result:" + "\n" + output) - return + raise Exception("Failed to retrieve task id") - # check for result directory and create it otherwise - if not os.path.exists(self.RESULTS_DIR): - LOGGER.debug('%s does not exist, we create it.', - self.RESULTS_DIR) - os.makedirs(self.RESULTS_DIR) - - # get and save rally operation JSON result - cmd = (["rally", "task", "detailed", task_id]) - LOGGER.debug('running command: %s', cmd) - proc = subprocess.Popen(cmd, stdout=subprocess.PIPE, - stderr=subprocess.STDOUT) - json_detailed = self.get_cmd_output(proc) - LOGGER.info('%s', json_detailed) - - cmd = (["rally", "task", "results", task_id]) - LOGGER.debug('running command: %s', cmd) - proc = subprocess.Popen(cmd, stdout=subprocess.PIPE, - stderr=subprocess.STDOUT) - json_results = self.get_cmd_output(proc) - self._append_summary(json_results, test_name) - report_json_name = 'opnfv-{}.json'.format(test_name) - report_json_dir = os.path.join(self.RESULTS_DIR, report_json_name) - with open(report_json_dir, 'w') as r_file: - LOGGER.debug('saving json file') - r_file.write(json_results) - - # write html report file - report_html_name = 'opnfv-{}.html'.format(test_name) - report_html_dir = os.path.join(self.RESULTS_DIR, report_html_name) - cmd = (["rally", "task", "report", task_id, "--out", report_html_dir]) - LOGGER.debug('running command: %s', cmd) - subprocess.Popen(cmd, stdout=subprocess.PIPE, - stderr=subprocess.STDOUT) - - # parse JSON operation result - if self.task_succeed(json_results): - LOGGER.info('Test scenario: "{}" OK.'.format(test_name) + "\n") - else: - LOGGER.info('Test scenario: "{}" Failed.'.format(test_name) + "\n") + self._save_results(test_name, task_id) def _append_summary(self, json_raw, test_name): """Update statistics summary info.""" @@ -400,20 +408,24 @@ class RallyBase(testcase.TestCase): overall_duration = 0.0 rally_report = json.loads(json_raw) - for report in rally_report: - if report.get('full_duration'): - overall_duration += report.get('full_duration') + for task in rally_report.get('tasks'): + for subtask in task.get('subtasks'): + for workload in subtask.get('workloads'): + if workload.get('full_duration'): + overall_duration += workload.get('full_duration') - if report.get('result'): - for result in report.get('result'): - nb_tests += 1 - if not result.get('error'): - nb_success += 1 + if workload.get('data'): + nb_tests += len(workload.get('data')) + + for result in workload.get('data'): + if not result.get('error'): + nb_success += 1 scenario_summary = {'test_name': test_name, 'overall_duration': overall_duration, 'nb_tests': nb_tests, - 'nb_success': nb_success} + 'nb_success': nb_success, + 'task_status': self.task_succeed(json_raw)} self.summary.append(scenario_summary) def _prepare_env(self): @@ -508,6 +520,7 @@ class RallyBase(testcase.TestCase): total_duration = 0.0 total_nb_tests = 0 total_nb_success = 0 + nb_modules = 0 payload = [] res_table = prettytable.PrettyTable( @@ -519,6 +532,8 @@ class RallyBase(testcase.TestCase): # for each scenario we draw a row for the table for item in self.summary: + if item['task_status'] is True: + nb_modules += 1 total_duration += item['overall_duration'] total_nb_tests += item['nb_tests'] total_nb_success += item['nb_success'] @@ -549,8 +564,9 @@ class RallyBase(testcase.TestCase): success_rate_str]) LOGGER.info("Rally Summary Report:\n\n%s\n", res_table.get_string()) - LOGGER.info("Rally '%s' success_rate is %s%%", - self.case_name, success_rate) + LOGGER.info("Rally '%s' success_rate is %s%% in %s/%s modules", + self.case_name, success_rate, nb_modules, + len(self.summary)) payload.append({'summary': {'duration': total_duration, 'nb tests': total_nb_tests, 'nb success': success_rate}}) @@ -573,6 +589,14 @@ class RallyBase(testcase.TestCase): if self.image: self.cloud.delete_image(self.image.id) + def is_successful(self): + """The overall result of the test.""" + for item in self.summary: + if item['task_status'] is False: + return testcase.TestCase.EX_TESTCASE_FAILED + + return super(RallyBase, self).is_successful() + @energy.enable_recording def run(self, **kwargs): """Run testcase.""" diff --git a/functest/opnfv_tests/openstack/tempest/tempest.py b/functest/opnfv_tests/openstack/tempest/tempest.py index 5ba1ed38a..11de144c9 100644 --- a/functest/opnfv_tests/openstack/tempest/tempest.py +++ b/functest/opnfv_tests/openstack/tempest/tempest.py @@ -428,9 +428,10 @@ class TempestResourcesManager(object): def _create_image(self, name): """Create image for tests""" LOGGER.info("Creating image with name: '%s'", name) + meta = getattr(config.CONF, 'openstack_extra_properties', None) image = self.cloud.create_image( name, filename=getattr(config.CONF, 'openstack_image_url'), - is_public=True) + is_public=True, meta=meta) LOGGER.debug("image: %s", image) return image diff --git a/functest/opnfv_tests/openstack/vping/vping_base.py b/functest/opnfv_tests/openstack/vping/vping_base.py index 2d1f856d7..2451c2de4 100644 --- a/functest/opnfv_tests/openstack/vping/vping_base.py +++ b/functest/opnfv_tests/openstack/vping/vping_base.py @@ -64,9 +64,12 @@ class VPingBase(testcase.TestCase): image_base_name = '{}-{}'.format( getattr(config.CONF, 'vping_image_name'), self.guid) self.logger.info("Creating image with name: '%s'", image_base_name) + meta = getattr(config.CONF, 'openstack_extra_properties', None) + self.logger.info("Image metadata: %s", meta) self.image = self.cloud.create_image( image_base_name, - filename=getattr(config.CONF, 'openstack_image_url')) + filename=getattr(config.CONF, 'openstack_image_url'), + meta=meta) self.logger.debug("image: %s", self.image) private_net_name = getattr( diff --git a/functest/opnfv_tests/sdn/odl/odl.py b/functest/opnfv_tests/sdn/odl/odl.py index 7c61e88df..cc56c6202 100644 --- a/functest/opnfv_tests/sdn/odl/odl.py +++ b/functest/opnfv_tests/sdn/odl/odl.py @@ -25,10 +25,9 @@ import os import re import sys +import os_client_config from six.moves import urllib -from snaps.openstack.utils import keystone_utils -from functest.opnfv_tests.openstack.snaps import snaps_utils from functest.utils import config from functest.utils import env from xtesting.core import robotframework @@ -157,9 +156,12 @@ class ODLTests(robotframework.RobotFramework): suites = kwargs["suites"] except KeyError: pass - snaps_creds = snaps_utils.get_credentials() - kwargs = {'neutronurl': keystone_utils.get_endpoint( - snaps_creds, 'network')} + cloud = os_client_config.make_shade() + neutron_id = cloud.search_services('neutron')[0].id + endpoint = cloud.search_endpoints( + filters={'interface': os.environ.get('OS_INTERFACE', 'public'), + 'service_id': neutron_id})[0].url + kwargs = {'neutronurl': endpoint} kwargs['odlip'] = env.get('SDN_CONTROLLER_IP') kwargs['odlwebport'] = '8080' kwargs['odlrestconfport'] = '8181' diff --git a/functest/opnfv_tests/vnf/epc/juju_epc.py b/functest/opnfv_tests/vnf/epc/juju_epc.py index 50253ccac..224d71114 100644 --- a/functest/opnfv_tests/vnf/epc/juju_epc.py +++ b/functest/opnfv_tests/vnf/epc/juju_epc.py @@ -137,7 +137,7 @@ class JujuEpc(vnf.VnfOnBoarding): name=name, password=str(uuid.uuid4()), project_name=self.tenant_name, - domain=self.snaps_creds.user_domain_name, + domain_name=self.snaps_creds.user_domain_name, roles={'_member_': self.tenant_name})) user_creator.create() self.created_object.append(user_creator) @@ -218,8 +218,12 @@ class JujuEpc(vnf.VnfOnBoarding): if ex.errno != errno.EEXIST: self.__logger.exception("Cannot create %s", self.res_dir) raise vnf.VnfPreparationException + + self.__logger.info("ENV:\n%s", env.string()) + self.public_auth_url = keystone_utils.get_endpoint( self.snaps_creds, 'identity') + # it enforces a versioned public identity endpoint as juju simply # adds /auth/tokens wich fails vs an unversioned endpoint. if not self.public_auth_url.endswith(('v3', 'v3/', 'v2.0', 'v2.0/')): @@ -236,7 +240,7 @@ class JujuEpc(vnf.VnfOnBoarding): Bootstrap juju """ - self.__logger.info("Deployed Orchestrator") + self.__logger.info("Deploying Juju Orchestrator") private_net_name = getattr( config.CONF, 'vnf_{}_private_net_name'.format(self.case_name)) private_subnet_name = '{}-{}'.format( @@ -249,7 +253,8 @@ class JujuEpc(vnf.VnfOnBoarding): getattr(config.CONF, 'vnf_{}_external_router'.format(self.case_name)), self.uuid) - self.__logger.info("Creating full network ...") + self.__logger.info("Creating full network with nameserver: %s", + env.get('NAMESERVER')) subnet_settings = SubnetConfig( name=private_subnet_name, cidr=private_subnet_cidr, @@ -277,6 +282,7 @@ class JujuEpc(vnf.VnfOnBoarding): flavor_creator = OpenStackFlavor(self.snaps_creds, flavor_settings) flavor_creator.create() self.created_object.append(flavor_creator) + self.__logger.info("Upload some OS images if it doesn't exist") images = get_config("tenant_images", self.config_file) self.__logger.info("Images needed for vEPC: %s", images) @@ -287,8 +293,7 @@ class JujuEpc(vnf.VnfOnBoarding): name=image_name, image_user='cloud', img_format='qcow2', image_file=image_file)) image_id = image_creator.create().id - cmd = ['timeout', '-t', JujuEpc.juju_timeout, - 'juju', 'metadata', 'generate-image', '-d', '/root', + cmd = ['juju', 'metadata', 'generate-image', '-d', '/root', '-i', image_id, '-s', image_name, '-r', self.snaps_creds.region_name, '-u', self.public_auth_url] @@ -296,18 +301,30 @@ class JujuEpc(vnf.VnfOnBoarding): self.__logger.info("%s\n%s", " ".join(cmd), output) self.created_object.append(image_creator) self.__logger.info("Network ID : %s", net_id) - cmd = ['timeout', '-t', JujuEpc.juju_timeout, - 'juju', 'bootstrap', 'abot-epc', 'abot-controller', - '--metadata-source', '/root', - '--constraints', 'mem=2G', - '--bootstrap-series', 'xenial', - '--config', 'network={}'.format(net_id), - '--config', 'ssl-hostname-verification=false', - '--config', 'use-floating-ip=true', - '--config', 'use-default-secgroup=true', - '--debug'] - output = subprocess.check_output(cmd, stderr=subprocess.STDOUT) - self.__logger.info("%s\n%s", " ".join(cmd), output) + + self.__logger.info("Starting Juju Bootstrap process...") + try: + cmd = ['timeout', '-t', JujuEpc.juju_timeout, + 'juju', 'bootstrap', 'abot-epc', 'abot-controller', + '--metadata-source', '/root', + '--constraints', 'mem=2G', + '--bootstrap-series', 'xenial', + '--config', 'network={}'.format(net_id), + '--config', 'ssl-hostname-verification=false', + '--config', 'use-floating-ip=true', + '--config', 'use-default-secgroup=true', + '--debug'] + output = subprocess.check_output(cmd, stderr=subprocess.STDOUT) + self.__logger.info("%s\n%s", " ".join(cmd), output) + except subprocess.CalledProcessError as cpe: + self.__logger.error( + "Exception with Juju Bootstrap: %s\n%s", + cpe.cmd, cpe.output) + return False + except Exception: # pylint: disable=broad-except + self.__logger.exception("Some issue with Juju Bootstrap ...") + return False + return True def check_app(self, name='abot-epc-basic', status='active'): @@ -336,15 +353,32 @@ class JujuEpc(vnf.VnfOnBoarding): flavor_creator.create() self.created_object.append(flavor_creator) self.__logger.info("Deploying Abot-epc bundle file ...") - cmd = ['timeout', '-t', JujuEpc.juju_timeout, - 'juju', 'deploy', '{}'.format(descriptor.get('file_name'))] + cmd = ['juju', 'deploy', '{}'.format(descriptor.get('file_name'))] output = subprocess.check_output(cmd, stderr=subprocess.STDOUT) self.__logger.info("%s\n%s", " ".join(cmd), output) self.__logger.info("Waiting for instances .....") - cmd = ['timeout', '-t', JujuEpc.juju_timeout, 'juju-wait'] + try: + cmd = ['timeout', '-t', JujuEpc.juju_timeout, 'juju-wait'] + output = subprocess.check_output(cmd, stderr=subprocess.STDOUT) + self.__logger.info("%s\n%s", " ".join(cmd), output) + self.__logger.info("Deployed Abot-epc on Openstack") + except subprocess.CalledProcessError as cpe: + self.__logger.error( + "Exception with Juju VNF Deployment: %s\n%s", + cpe.cmd, cpe.output) + return False + except Exception: # pylint: disable=broad-except + self.__logger.exception("Some issue with the VNF Deployment ..") + return False + + self.__logger.info("Checking status of ABot and EPC units ...") + cmd = ['juju', 'status'] output = subprocess.check_output(cmd, stderr=subprocess.STDOUT) - self.__logger.info("%s\n%s", " ".join(cmd), output) - self.__logger.info("Deployed Abot-epc on Openstack") + self.__logger.debug("%s\n%s", " ".join(cmd), output) + for app in ['abot-epc-basic', 'oai-epc', 'oai-hss']: + if not self.check_app(app): + return False + nova_client = nova_utils.nova_client(self.snaps_creds) instances = get_instances(nova_client) self.__logger.info("List of Instance: %s", instances) @@ -360,22 +394,18 @@ class JujuEpc(vnf.VnfOnBoarding): # This will add sctp rule to a common Security Group Created # by juju and shared to all deployed units. self._add_custom_rule(sec_group) - cmd = ['juju', 'status'] - output = subprocess.check_output(cmd, stderr=subprocess.STDOUT) - self.__logger.debug("%s\n%s", " ".join(cmd), output) - for app in ['abot-epc-basic', 'oai-epc', 'oai-hss']: - if not self.check_app(app): - return False - self.__logger.info("Copying the feature files to Abot_node ") + + self.__logger.info("Transferring the feature files to Abot_node ...") cmd = ['timeout', '-t', JujuEpc.juju_timeout, 'juju', 'scp', '--', '-r', '-v', '{}/featureFiles'.format(self.case_dir), 'abot-epc-basic/0:~/'] output = subprocess.check_output(cmd, stderr=subprocess.STDOUT) self.__logger.info("%s\n%s", " ".join(cmd), output) - self.__logger.info("Copying the feature files in Abot_node ") + + self.__logger.info("Copying the feature files within Abot_node ") cmd = ['timeout', '-t', JujuEpc.juju_timeout, 'juju', 'ssh', 'abot-epc-basic/0', - 'sudo', 'rsync', '-azvv', '~/featureFiles', + 'sudo', 'cp', '-vfR', '~/featureFiles/*', '/etc/rebaca-test-suite/featureFiles'] output = subprocess.check_output(cmd, stderr=subprocess.STDOUT) self.__logger.info("%s\n%s", " ".join(cmd), output) @@ -385,14 +415,15 @@ class JujuEpc(vnf.VnfOnBoarding): """Run test on ABoT.""" start_time = time.time() self.__logger.info("Running VNF Test cases....") - cmd = ['timeout', '-t', JujuEpc.juju_timeout, - 'juju', 'run-action', 'abot-epc-basic/0', 'run', + cmd = ['juju', 'run-action', 'abot-epc-basic/0', 'run', 'tagnames={}'.format(self.details['test_vnf']['tag_name'])] output = subprocess.check_output(cmd, stderr=subprocess.STDOUT) self.__logger.info("%s\n%s", " ".join(cmd), output) + cmd = ['timeout', '-t', JujuEpc.juju_timeout, 'juju-wait'] output = subprocess.check_output(cmd, stderr=subprocess.STDOUT) self.__logger.info("%s\n%s", " ".join(cmd), output) + duration = time.time() - start_time self.__logger.info("Getting results from Abot node....") cmd = ['timeout', '-t', JujuEpc.juju_timeout, @@ -429,8 +460,12 @@ class JujuEpc(vnf.VnfOnBoarding): '--destroy-all-models'] output = subprocess.check_output(cmd, stderr=subprocess.STDOUT) self.__logger.info("%s\n%s", " ".join(cmd), output) + except subprocess.CalledProcessError as cpe: + self.__logger.error( + "Exception with Juju Cleanup: %s\n%s", + cpe.cmd, cpe.output) except Exception: # pylint: disable=broad-except - self.__logger.exception("Some issue during the undeployment ..") + self.__logger.exception("General issue during the undeployment ..") if not self.orchestrator['requirements']['preserve_setup']: self.__logger.info('Remove the Abot_epc OS object ..') diff --git a/functest/opnfv_tests/vnf/ims/cloudify_ims.py b/functest/opnfv_tests/vnf/ims/cloudify_ims.py index 6180e2c8f..b3b0ee4a9 100644 --- a/functest/opnfv_tests/vnf/ims/cloudify_ims.py +++ b/functest/opnfv_tests/vnf/ims/cloudify_ims.py @@ -12,6 +12,7 @@ import logging import os import time +import uuid from cloudify_rest_client import CloudifyClient from cloudify_rest_client.executions import Execution @@ -25,6 +26,7 @@ from snaps.config.network import NetworkConfig, PortConfig, SubnetConfig from snaps.config.router import RouterConfig from snaps.config.security_group import ( Direction, Protocol, SecurityGroupConfig, SecurityGroupRuleConfig) +from snaps.config.user import UserConfig from snaps.config.vm_inst import FloatingIpConfig, VmInstanceConfig from snaps.openstack.create_flavor import OpenStackFlavor from snaps.openstack.create_image import OpenStackImage @@ -33,6 +35,7 @@ from snaps.openstack.create_keypairs import OpenStackKeypair from snaps.openstack.create_network import OpenStackNetwork from snaps.openstack.create_router import OpenStackRouter from snaps.openstack.create_security_group import OpenStackSecurityGroup +from snaps.openstack.create_user import OpenStackUser from snaps.openstack.utils import keystone_utils from xtesting.energy import energy @@ -112,19 +115,6 @@ class CloudifyIms(clearwater_ims_base.ClearwaterOnBoardingBase): compute_quotas = self.os_project.update_compute_quotas(compute_quotas) network_quotas = self.os_project.update_network_quotas(network_quotas) - # needs some images - self.__logger.info("Upload some OS images if it doesn't exist") - for image_name, image_file in self.images.iteritems(): - self.__logger.info("image: %s, file: %s", image_name, image_file) - if image_file and image_name: - image_creator = OpenStackImage( - self.snaps_creds, - ImageConfig( - name=image_name, image_user='cloud', - img_format='qcow2', image_file=image_file)) - image_creator.create() - self.created_object.append(image_creator) - def deploy_orchestrator(self): # pylint: disable=too-many-locals,too-many-statements """ @@ -132,18 +122,59 @@ class CloudifyIms(clearwater_ims_base.ClearwaterOnBoardingBase): network, security group, fip, VM creation """ - # network creation - start_time = time.time() + + # orchestrator VM flavor + self.__logger.info("Get or create flavor for cloudify manager vm ...") + flavor_settings = FlavorConfig( + name="{}-{}".format( + self.orchestrator['requirements']['flavor']['name'], + self.uuid), + ram=self.orchestrator['requirements']['flavor']['ram_min'], + disk=50, + vcpus=2) + flavor_creator = OpenStackFlavor(self.snaps_creds, flavor_settings) + flavor_creator.create() + self.created_object.append(flavor_creator) + + self.__logger.info("Creating a second user to bypass issues ...") + user_creator = OpenStackUser( + self.snaps_creds, + UserConfig( + name='cloudify_network_bug-{}'.format(self.uuid), + password=str(uuid.uuid4()), + project_name=self.tenant_name, + domain_name=self.snaps_creds.user_domain_name, + roles={'_member_': self.tenant_name})) + user_creator.create() + self.created_object.append(user_creator) + + snaps_creds = user_creator.get_os_creds(self.snaps_creds.project_name) + self.__logger.debug("snaps creds: %s", snaps_creds) + self.__logger.info("Creating keypair ...") kp_file = os.path.join(self.data_dir, "cloudify_ims.pem") keypair_settings = KeypairConfig( name='cloudify_ims_kp-{}'.format(self.uuid), private_filepath=kp_file) - keypair_creator = OpenStackKeypair(self.snaps_creds, keypair_settings) + keypair_creator = OpenStackKeypair(snaps_creds, keypair_settings) keypair_creator.create() self.created_object.append(keypair_creator) + # needs some images + self.__logger.info("Upload some OS images if it doesn't exist") + for image_name, image_file in self.images.iteritems(): + self.__logger.info("image: %s, file: %s", image_name, image_file) + if image_file and image_name: + image_creator = OpenStackImage( + snaps_creds, + ImageConfig( + name=image_name, image_user='cloud', + img_format='qcow2', image_file=image_file)) + image_creator.create() + self.created_object.append(image_creator) + + # network creation self.__logger.info("Creating full network ...") subnet_settings = SubnetConfig( name='cloudify_ims_subnet-{}'.format(self.uuid), @@ -152,12 +183,12 @@ class CloudifyIms(clearwater_ims_base.ClearwaterOnBoardingBase): network_settings = NetworkConfig( name='cloudify_ims_network-{}'.format(self.uuid), subnet_settings=[subnet_settings]) - network_creator = OpenStackNetwork(self.snaps_creds, network_settings) + network_creator = OpenStackNetwork(snaps_creds, network_settings) network_creator.create() self.created_object.append(network_creator) - ext_net_name = snaps_utils.get_ext_net_name(self.snaps_creds) + ext_net_name = snaps_utils.get_ext_net_name(snaps_creds) router_creator = OpenStackRouter( - self.snaps_creds, + snaps_creds, RouterConfig( name='cloudify_ims_router-{}'.format(self.uuid), external_gateway=ext_net_name, @@ -178,36 +209,21 @@ class CloudifyIms(clearwater_ims_base.ClearwaterOnBoardingBase): sec_grp_name="sg-cloudify-manager-{}".format(self.uuid), direction=Direction.ingress, protocol=Protocol.udp, port_range_min=1, port_range_max=65535)) - security_group_creator = OpenStackSecurityGroup( - self.snaps_creds, + snaps_creds, SecurityGroupConfig( name="sg-cloudify-manager-{}".format(self.uuid), rule_settings=sg_rules)) - security_group_creator.create() self.created_object.append(security_group_creator) - # orchestrator VM flavor - self.__logger.info("Get or create flavor for cloudify manager vm ...") - - flavor_settings = FlavorConfig( - name=self.orchestrator['requirements']['flavor']['name'], - ram=self.orchestrator['requirements']['flavor']['ram_min'], - disk=50, - vcpus=2) - flavor_creator = OpenStackFlavor(self.snaps_creds, flavor_settings) - flavor_creator.create() - self.created_object.append(flavor_creator) image_settings = ImageConfig( name=self.orchestrator['requirements']['os_image'], image_user='centos', exists=True) - port_settings = PortConfig( name='cloudify_manager_port-{}'.format(self.uuid), network_name=network_settings.name) - manager_settings = VmInstanceConfig( name='cloudify_manager-{}'.format(self.uuid), flavor=flavor_settings.name, @@ -218,26 +234,23 @@ class CloudifyIms(clearwater_ims_base.ClearwaterOnBoardingBase): name='cloudify_manager_fip-{}'.format(self.uuid), port_name=port_settings.name, router_name=router_creator.router_settings.name)]) - manager_creator = OpenStackVmInstance( - self.snaps_creds, manager_settings, image_settings, + snaps_creds, manager_settings, image_settings, keypair_settings) - self.__logger.info("Creating cloudify manager VM") manager_creator.create() self.created_object.append(manager_creator) - public_auth_url = keystone_utils.get_endpoint( - self.snaps_creds, 'identity') + public_auth_url = keystone_utils.get_endpoint(snaps_creds, 'identity') cfy_creds = dict( - keystone_username=self.snaps_creds.username, - keystone_password=self.snaps_creds.password, - keystone_tenant_name=self.snaps_creds.project_name, + keystone_username=snaps_creds.username, + keystone_password=snaps_creds.password, + keystone_tenant_name=snaps_creds.project_name, keystone_url=public_auth_url, - region=self.snaps_creds.region_name, - user_domain_name=self.snaps_creds.user_domain_name, - project_domain_name=self.snaps_creds.project_domain_name) + region=snaps_creds.region_name, + user_domain_name=snaps_creds.user_domain_name, + project_domain_name=snaps_creds.project_domain_name) self.__logger.info("Set creds for cloudify manager %s", cfy_creds) cfy_client = CloudifyClient( @@ -247,36 +260,35 @@ class CloudifyIms(clearwater_ims_base.ClearwaterOnBoardingBase): self.orchestrator['object'] = cfy_client self.__logger.info("Attemps running status of the Manager") - cfy_status = None - retry = 10 - while str(cfy_status) != 'running' and retry: + for loop in range(10): try: + self.__logger.debug( + "status %s", cfy_client.manager.get_status()) cfy_status = cfy_client.manager.get_status()['status'] self.__logger.info( "The current manager status is %s", cfy_status) + if str(cfy_status) != 'running': + raise Exception("Cloudify Manager isn't up and running") + self.__logger.info("Put OpenStack creds in manager") + secrets_list = cfy_client.secrets.list() + for k, val in cfy_creds.iteritems(): + if not any(d.get('key', None) == k for d in secrets_list): + cfy_client.secrets.create(k, val) + else: + cfy_client.secrets.update(k, val) + break except Exception: # pylint: disable=broad-except - self.__logger.info( - "Cloudify Manager isn't up and running. Retrying ...") - retry = retry - 1 - time.sleep(30) - - if str(cfy_status) == 'running': - self.__logger.info("Cloudify Manager is up and running") + self.logger.info( + "try %s: Cloudify Manager isn't up and running", loop + 1) + time.sleep(30) else: - raise Exception("Cloudify Manager isn't up and running") - - self.__logger.info("Put OpenStack creds in manager") - secrets_list = cfy_client.secrets.list() - for k, val in cfy_creds.iteritems(): - if not any(d.get('key', None) == k for d in secrets_list): - cfy_client.secrets.create(k, val) - else: - cfy_client.secrets.update(k, val) + self.logger.error("Cloudify Manager isn't up and running") + return False duration = time.time() - start_time - self.__logger.info("Put private keypair in manager") if manager_creator.vm_ssh_active(block=True): + self.__logger.info("Put private keypair in manager") ssh = manager_creator.ssh_client() scp = SCPClient(ssh.get_transport(), socket_timeout=15.0) scp.put(kp_file, '~/') @@ -287,6 +299,10 @@ class CloudifyIms(clearwater_ims_base.ClearwaterOnBoardingBase): cmd = "sudo yum install -y gcc python-devel" self.run_blocking_ssh_command( ssh, cmd, "Unable to install packages on manager") + self.run_blocking_ssh_command(ssh, 'cfy status') + else: + self.__logger.error("Cannot connect to manager") + return False self.details['orchestrator'].update(status='PASS', duration=duration) @@ -305,22 +321,22 @@ class CloudifyIms(clearwater_ims_base.ClearwaterOnBoardingBase): self.__logger.info("Upload VNFD") cfy_client = self.orchestrator['object'] descriptor = self.vnf['descriptor'] - cfy_client.blueprints.publish_archive(descriptor.get('url'), - descriptor.get('name'), - descriptor.get('file_name')) - + cfy_client.blueprints.upload( + descriptor.get('file_name'), descriptor.get('name')) self.__logger.info("Get or create flavor for all clearwater vm") flavor_settings = FlavorConfig( - name=self.vnf['requirements']['flavor']['name'], + name="{}-{}".format( + self.vnf['requirements']['flavor']['name'], + self.uuid), ram=self.vnf['requirements']['flavor']['ram_min'], disk=25, - vcpus=1) + vcpus=2) flavor_creator = OpenStackFlavor(self.snaps_creds, flavor_settings) flavor_creator.create() self.created_object.append(flavor_creator) self.vnf['inputs'].update(dict( - flavor_id=self.vnf['requirements']['flavor']['name'], + flavor_id=flavor_settings.name, )) self.__logger.info("Create VNF Instance") @@ -338,7 +354,8 @@ class CloudifyIms(clearwater_ims_base.ClearwaterOnBoardingBase): execution = cfy_client.executions.start(descriptor.get('name'), 'install') # Show execution log - execution = wait_for_execution(cfy_client, execution, self.__logger) + execution = wait_for_execution( + cfy_client, execution, self.__logger, timeout=3600) duration = time.time() - start_time @@ -458,7 +475,7 @@ def get_config(parameter, file_path): return value -def wait_for_execution(client, execution, logger, timeout=1500, ): +def wait_for_execution(client, execution, logger, timeout=3600, ): """Wait for a workflow execution on Cloudify Manager.""" # if execution already ended - return without waiting if execution.status in Execution.END_STATES: @@ -478,7 +495,7 @@ def wait_for_execution(client, execution, logger, timeout=1500, ): execution_id=execution.id, _offset=offset, _size=batch_size, - include_logs=False, + include_logs=True, sort='@timestamp').items offset = offset + len(event_list) diff --git a/functest/opnfv_tests/vnf/ims/cloudify_ims.yaml b/functest/opnfv_tests/vnf/ims/cloudify_ims.yaml index 4586dfd33..a40fcc6b3 100644 --- a/functest/opnfv_tests/vnf/ims/cloudify_ims.yaml +++ b/functest/opnfv_tests/vnf/ims/cloudify_ims.yaml @@ -9,21 +9,19 @@ orchestrator: version: '4.0' requirements: flavor: - name: m1.medium + name: cloudify.medium ram_min: 4096 os_image: 'cloudify_manager_4.0' vnf: name: clearwater version: '107' descriptor: - file_name: openstack-blueprint.yaml + file_name: /src/vims/openstack-blueprint.yaml name: clearwater-opnfv - url: - https://github.com/Orange-OpenSource/opnfv-cloudify-clearwater/archive/master.zip version: '122' requirements: flavor: - name: m1.small + name: cloudify.small ram_min: 2048 compute_quotas: cores: 50 @@ -34,7 +32,7 @@ vnf: port: 50 inputs: image_id: 'ubuntu_14.04' - flavor_id: 'm1.small' + flavor_id: 'cloudify.small' agent_user: ubuntu key_pair_name: cloudify_ims_kp private_key_path: '/etc/cloudify/cloudify_ims.pem' diff --git a/functest/opnfv_tests/vnf/ims/cloudify_ims_perf.yaml b/functest/opnfv_tests/vnf/ims/cloudify_ims_perf.yaml index 0e020cbe4..a6633dfc1 100644 --- a/functest/opnfv_tests/vnf/ims/cloudify_ims_perf.yaml +++ b/functest/opnfv_tests/vnf/ims/cloudify_ims_perf.yaml @@ -22,10 +22,8 @@ vnf: name: clearwater version: '107' descriptor: - file_name: openstack-blueprint-with-numbers.yaml + file_name: /src/vims/openstack-blueprint-with-numbers.yaml name: clearwater-opnfv - url: - https://github.com/Orange-OpenSource/opnfv-cloudify-clearwater/archive/master.zip version: '122' requirements: flavor: diff --git a/functest/opnfv_tests/vnf/router/cloudify_vrouter.py b/functest/opnfv_tests/vnf/router/cloudify_vrouter.py index 9f6327b78..11f30bf4d 100644 --- a/functest/opnfv_tests/vnf/router/cloudify_vrouter.py +++ b/functest/opnfv_tests/vnf/router/cloudify_vrouter.py @@ -27,8 +27,6 @@ from functest.utils import config from functest.utils import env from functest.utils import functest_utils -from git import Repo - from snaps.config.flavor import FlavorConfig from snaps.config.image import ImageConfig from snaps.config.keypair import KeypairConfig @@ -136,17 +134,6 @@ class CloudifyVrouter(vrouter_base.VrouterOnBoardingBase): super(CloudifyVrouter, self).prepare() self.__logger.info("Additional pre-configuration steps") self.util.set_credentials(self.snaps_creds) - self.__logger.info("Upload some OS images if it doesn't exist") - for image_name, image_file in self.images.iteritems(): - self.__logger.info("image: %s, file: %s", image_name, image_file) - if image_file and image_name: - image_creator = OpenStackImage( - self.snaps_creds, - ImageConfig( - name=image_name, image_user='cloud', - img_format='qcow2', image_file=image_file)) - image_creator.create() - self.created_object.append(image_creator) def deploy_orchestrator(self): # pylint: disable=too-many-locals,too-many-statements @@ -156,15 +143,54 @@ class CloudifyVrouter(vrouter_base.VrouterOnBoardingBase): """ # network creation start_time = time.time() + + # orchestrator VM flavor + self.__logger.info("Get or create flavor for cloudify manager vm ...") + flavor_settings = FlavorConfig( + name="{}-{}".format( + self.orchestrator['requirements']['flavor']['name'], + self.uuid), + ram=self.orchestrator['requirements']['flavor']['ram_min'], + disk=50, vcpus=2) + flavor_creator = OpenStackFlavor(self.snaps_creds, flavor_settings) + flavor_creator.create() + self.created_object.append(flavor_creator) + + user_creator = OpenStackUser( + self.snaps_creds, + UserConfig( + name='cloudify_network_bug-{}'.format(self.uuid), + password=str(uuid.uuid4()), + project_name=self.tenant_name, + domain_name=self.snaps_creds.user_domain_name, + roles={'_member_': self.tenant_name})) + user_creator.create() + self.created_object.append(user_creator) + + snaps_creds = user_creator.get_os_creds(self.snaps_creds.project_name) + self.__logger.debug("snaps creds: %s", snaps_creds) + self.__logger.info("Creating keypair ...") kp_file = os.path.join(self.data_dir, "cloudify_vrouter.pem") keypair_settings = KeypairConfig( name='cloudify_vrouter_kp-{}'.format(self.uuid), private_filepath=kp_file) - keypair_creator = OpenStackKeypair(self.snaps_creds, keypair_settings) + keypair_creator = OpenStackKeypair(snaps_creds, keypair_settings) keypair_creator.create() self.created_object.append(keypair_creator) + self.__logger.info("Upload some OS images if it doesn't exist") + for image_name, image_file in self.images.iteritems(): + self.__logger.info("image: %s, file: %s", image_name, image_file) + if image_file and image_name: + image_creator = OpenStackImage( + snaps_creds, + ImageConfig( + name=image_name, image_user='cloud', + img_format='qcow2', image_file=image_file)) + image_creator.create() + self.created_object.append(image_creator) + self.__logger.info("Creating full network ...") subnet_settings = SubnetConfig( name='cloudify_vrouter_subnet-{}'.format(self.uuid), @@ -173,12 +199,12 @@ class CloudifyVrouter(vrouter_base.VrouterOnBoardingBase): network_settings = NetworkConfig( name='cloudify_vrouter_network-{}'.format(self.uuid), subnet_settings=[subnet_settings]) - network_creator = OpenStackNetwork(self.snaps_creds, network_settings) + network_creator = OpenStackNetwork(snaps_creds, network_settings) network_creator.create() self.created_object.append(network_creator) - ext_net_name = snaps_utils.get_ext_net_name(self.snaps_creds) + ext_net_name = snaps_utils.get_ext_net_name(snaps_creds) router_creator = OpenStackRouter( - self.snaps_creds, + snaps_creds, RouterConfig( name='cloudify_vrouter_router-{}'.format(self.uuid), external_gateway=ext_net_name, @@ -201,34 +227,20 @@ class CloudifyVrouter(vrouter_base.VrouterOnBoardingBase): direction=Direction.ingress, protocol=Protocol.udp, port_range_min=1, port_range_max=65535)) - security_group_creator = OpenStackSecurityGroup( - self.snaps_creds, + snaps_creds, SecurityGroupConfig( name="sg-cloudify-manager-{}".format(self.uuid), rule_settings=sg_rules)) - security_group_creator.create() self.created_object.append(security_group_creator) - # orchestrator VM flavor - self.__logger.info("Get or create flavor for cloudify manager vm ...") - - flavor_settings = FlavorConfig( - name=self.orchestrator['requirements']['flavor']['name'], - ram=self.orchestrator['requirements']['flavor']['ram_min'], - disk=50, vcpus=2) - flavor_creator = OpenStackFlavor(self.snaps_creds, flavor_settings) - flavor_creator.create() - self.created_object.append(flavor_creator) image_settings = ImageConfig( name=self.orchestrator['requirements']['os_image'], image_user='centos', exists=True) - port_settings = PortConfig( name='cloudify_manager_port-{}'.format(self.uuid), network_name=network_settings.name) - manager_settings = VmInstanceConfig( name='cloudify_manager-{}'.format(self.uuid), flavor=flavor_settings.name, @@ -239,9 +251,8 @@ class CloudifyVrouter(vrouter_base.VrouterOnBoardingBase): name='cloudify_manager_fip-{}'.format(self.uuid), port_name=port_settings.name, router_name=router_creator.router_settings.name)]) - manager_creator = OpenStackVmInstance( - self.snaps_creds, manager_settings, image_settings, + snaps_creds, manager_settings, image_settings, keypair_settings) self.__logger.info("Creating cloudify manager VM") @@ -257,23 +268,23 @@ class CloudifyVrouter(vrouter_base.VrouterOnBoardingBase): self.cfy_manager_ip = manager_creator.get_floating_ip().ip self.__logger.info("Attemps running status of the Manager") - cfy_status = None - retry = 10 - while str(cfy_status) != 'running' and retry: + for loop in range(10): try: + self.__logger.debug( + "status %s", cfy_client.manager.get_status()) cfy_status = cfy_client.manager.get_status()['status'] self.__logger.info( "The current manager status is %s", cfy_status) + if str(cfy_status) != 'running': + raise Exception("Cloudify Manager isn't up and running") + break except Exception: # pylint: disable=broad-except - self.__logger.info( - "Cloudify Manager isn't up and running. Retrying ...") - retry = retry - 1 - time.sleep(30) - - if str(cfy_status) == 'running': - self.__logger.info("Cloudify Manager is up and running") + self.logger.info( + "try %s: Cloudify Manager isn't up and running", loop + 1) + time.sleep(30) else: - raise Exception("Cloudify Manager isn't up and running") + self.logger.error("Cloudify Manager isn't up and running") + return False duration = time.time() - start_time @@ -289,35 +300,17 @@ class CloudifyVrouter(vrouter_base.VrouterOnBoardingBase): cmd = "sudo yum install -y gcc python-devel" self.run_blocking_ssh_command( ssh, cmd, "Unable to install packages on manager") + else: + self.__logger.error("Cannot connect to manager") + return False self.details['orchestrator'].update(status='PASS', duration=duration) - self.vnf['inputs'].update(dict(external_network_name=ext_net_name)) - - return True - - def deploy_vnf(self): - start_time = time.time() - - self.__logger.info("Upload VNFD") - cfy_client = self.orchestrator['object'] - descriptor = self.vnf['descriptor'] - self.deployment_name = descriptor.get('name') - - vrouter_blueprint_dir = os.path.join( - self.data_dir, self.util.blueprint_dir) - if not os.path.exists(vrouter_blueprint_dir): - Repo.clone_from( - descriptor.get('url'), vrouter_blueprint_dir, - branch=descriptor.get('version')) - - cfy_client.blueprints.upload( - vrouter_blueprint_dir + self.util.blueprint_file_name, - descriptor.get('name')) - self.__logger.info("Get or create flavor for vrouter") flavor_settings = FlavorConfig( - name=self.vnf['requirements']['flavor']['name'], + name="{}-{}".format( + self.vnf['requirements']['flavor']['name'], + self.uuid), ram=self.vnf['requirements']['flavor']['ram_min'], disk=25, vcpus=1) flavor_creator = OpenStackFlavor(self.snaps_creds, flavor_settings) @@ -325,22 +318,9 @@ class CloudifyVrouter(vrouter_base.VrouterOnBoardingBase): self.created_object.append(flavor_creator) # set image name - glance = glance_utils.glance_client(self.snaps_creds) + glance = glance_utils.glance_client(snaps_creds) image = glance_utils.get_image(glance, "vyos1.1.7") - - user_creator = OpenStackUser( - self.snaps_creds, - UserConfig( - name='cloudify_network_bug-{}'.format(self.uuid), - password=str(uuid.uuid4()), - project_name=self.tenant_name, - domain=self.snaps_creds.user_domain_name, - roles={'_member_': self.tenant_name})) - user_creator.create() - self.created_object.append(user_creator) - snaps_creds = user_creator.get_os_creds(self.snaps_creds.project_name) - self.__logger.debug("snaps creds: %s", snaps_creds) - + self.vnf['inputs'].update(dict(external_network_name=ext_net_name)) self.vnf['inputs'].update(dict(target_vnf_image_id=image.id)) self.vnf['inputs'].update(dict(reference_vnf_image_id=image.id)) self.vnf['inputs'].update(dict(target_vnf_flavor_id=flavor.id)) @@ -361,6 +341,24 @@ class CloudifyVrouter(vrouter_base.VrouterOnBoardingBase): keystone_url=keystone_utils.get_endpoint( snaps_creds, 'identity'))) + credentials = {"snaps_creds": snaps_creds} + self.util_info = {"credentials": credentials, + "cfy": cfy_client, + "vnf_data_dir": self.util.vnf_data_dir} + + return True + + def deploy_vnf(self): + start_time = time.time() + + self.__logger.info("Upload VNFD") + cfy_client = self.orchestrator['object'] + descriptor = self.vnf['descriptor'] + self.deployment_name = descriptor.get('name') + + cfy_client.blueprints.upload( + descriptor.get('file_name'), descriptor.get('name')) + self.__logger.info("Create VNF Instance") cfy_client.deployments.create( descriptor.get('name'), descriptor.get('name'), @@ -388,19 +386,9 @@ class CloudifyVrouter(vrouter_base.VrouterOnBoardingBase): return result def test_vnf(self): - cfy_client = self.orchestrator['object'] - credentials = {"snaps_creds": self.snaps_creds} - - self.util_info = {"credentials": credentials, - "cfy": cfy_client, - "vnf_data_dir": self.util.vnf_data_dir} - start_time = time.time() - result, test_result_data = super(CloudifyVrouter, self).test_vnf() - duration = time.time() - start_time - if result: self.details['test_vnf'].update( status='PASS', result='OK', full_result=test_result_data, @@ -409,7 +397,6 @@ class CloudifyVrouter(vrouter_base.VrouterOnBoardingBase): self.details['test_vnf'].update( status='FAIL', result='NG', full_result=test_result_data, duration=duration) - return True def clean(self): @@ -461,7 +448,7 @@ def wait_for_execution(client, execution, logger, timeout=7200, ): while True: event_list = client.events.list( execution_id=execution.id, _offset=offset, _size=batch_size, - include_logs=False, sort='@timestamp').items + include_logs=True, sort='@timestamp').items offset = offset + len(event_list) for event in event_list: diff --git a/functest/opnfv_tests/vnf/router/cloudify_vrouter.yaml b/functest/opnfv_tests/vnf/router/cloudify_vrouter.yaml index 58bdb66a3..649cd6ccd 100644 --- a/functest/opnfv_tests/vnf/router/cloudify_vrouter.yaml +++ b/functest/opnfv_tests/vnf/router/cloudify_vrouter.yaml @@ -5,25 +5,26 @@ tenant_images: vyos1.1.7: /home/opnfv/functest/images/vyos-1.1.7.img test_data: url: 'https://github.com/oolorg/opnfv-vnf-data.git' - branch: 'master' + branch: 'fraser' orchestrator: name: cloudify version: '4.0' requirements: flavor: - name: m1.medium + name: cloudify.medium ram_min: 4096 os_image: 'cloudify_manager_4.0' vnf: name: vyos1.1.7 version: '1.1.7' descriptor: - url: https://github.com/oolorg/opnfv-vnf-vyos-blueprint/ + file_name: + /src/opnfv-vnf-vyos-blueprint/function-test-openstack-blueprint.yaml name: vrouter-opnfv - version: 'master' + version: fraser requirements: flavor: - name: m1.medium + name: cloudify.medium ram_min: 2048 inputs: external_network_name: admin_floating_net diff --git a/functest/tests/unit/odl/test_odl.py b/functest/tests/unit/odl/test_odl.py index 6304d37a3..d1dfea8a7 100644 --- a/functest/tests/unit/odl/test_odl.py +++ b/functest/tests/unit/odl/test_odl.py @@ -14,6 +14,7 @@ import os import unittest import mock +import munch from robot.errors import RobotError import six from six.moves import urllib @@ -33,6 +34,7 @@ class ODLTesting(unittest.TestCase): _keystone_ip = "127.0.0.1" _neutron_url = u"https://127.0.0.1:9696" + _neutron_id = u"dummy" _sdn_controller_ip = "127.0.0.3" _os_auth_url = "http://{}:5000/v3".format(_keystone_ip) _os_projectname = "admin" @@ -44,6 +46,7 @@ class ODLTesting(unittest.TestCase): _odl_password = "admin" _os_userdomainname = 'Default' _os_projectdomainname = 'Default' + _os_interface = "public" def setUp(self): for var in ("INSTALLER_TYPE", "SDN_CONTROLLER", "SDN_CONTROLLER_IP"): @@ -56,6 +59,7 @@ class ODLTesting(unittest.TestCase): os.environ["OS_PROJECT_NAME"] = self._os_projectname os.environ["OS_PROJECT_DOMAIN_NAME"] = self._os_projectdomainname os.environ["OS_PASSWORD"] = self._os_password + os.environ["OS_INTERFACE"] = self._os_interface self.test = odl.ODLTests(case_name='odl', project_name='functest') self.defaultargs = {'odlusername': self._odl_username, 'odlpassword': self._odl_password, @@ -265,35 +269,98 @@ class ODLMainTesting(ODLTesting): class ODLRunTesting(ODLTesting): - """The class testing ODLTests.run().""" - # pylint: disable=missing-docstring + # pylint: disable=too-many-public-methods,missing-docstring + + @mock.patch('os_client_config.make_shade', side_effect=Exception) + def test_no_cloud(self, *args): + self.assertEqual(self.test.run(), testcase.TestCase.EX_RUN_ERROR) + args[0].assert_called_once_with() + + @mock.patch('os_client_config.make_shade') + def test_no_service1(self, *args): + args[0].return_value.search_services.return_value = None + self.assertEqual(self.test.run(), testcase.TestCase.EX_RUN_ERROR) + args[0].return_value.search_services.assert_called_once_with('neutron') + args[0].return_value.search_endpoints.assert_not_called() + + @mock.patch('os_client_config.make_shade') + def test_no_service2(self, *args): + args[0].return_value.search_services.return_value = [] + self.assertEqual(self.test.run(), testcase.TestCase.EX_RUN_ERROR) + args[0].return_value.search_services.assert_called_once_with('neutron') + args[0].return_value.search_endpoints.assert_not_called() - @mock.patch('snaps.openstack.utils.keystone_utils.get_endpoint', - return_value=ODLTesting._neutron_url) - @mock.patch('functest.opnfv_tests.openstack.snaps.snaps_utils.' - 'get_credentials') + @mock.patch('os_client_config.make_shade') + def test_no_service3(self, *args): + args[0].return_value.search_services.return_value = [ + munch.Munch()] + self.assertEqual(self.test.run(), testcase.TestCase.EX_RUN_ERROR) + args[0].return_value.search_services.assert_called_once_with('neutron') + args[0].return_value.search_endpoints.assert_not_called() + + @mock.patch('os_client_config.make_shade') + def test_no_endpoint1(self, *args): + args[0].return_value.search_services.return_value = [ + munch.Munch(id=self._neutron_id)] + args[0].return_value.search_endpoints.return_value = None + self.assertEqual(self.test.run(), testcase.TestCase.EX_RUN_ERROR) + args[0].return_value.search_services.assert_called_once_with('neutron') + args[0].return_value.search_endpoints.assert_called_once_with( + filters={'interface': self._os_interface, + 'service_id': self._neutron_id}) + + @mock.patch('os_client_config.make_shade') + def test_no_endpoint2(self, *args): + args[0].return_value.search_services.return_value = [ + munch.Munch(id=self._neutron_id)] + args[0].return_value.search_endpoints.return_value = [] + self.assertEqual(self.test.run(), testcase.TestCase.EX_RUN_ERROR) + args[0].return_value.search_services.assert_called_once_with('neutron') + args[0].return_value.search_endpoints.assert_called_once_with( + filters={'interface': self._os_interface, + 'service_id': self._neutron_id}) + + @mock.patch('os_client_config.make_shade') + def test_no_endpoint3(self, *args): + args[0].return_value.search_services.return_value = [ + munch.Munch(id=self._neutron_id)] + args[0].return_value.search_endpoints.return_value = [munch.Munch()] + self.assertEqual(self.test.run(), testcase.TestCase.EX_RUN_ERROR) + args[0].return_value.search_services.assert_called_once_with('neutron') + args[0].return_value.search_endpoints.assert_called_once_with( + filters={'interface': self._os_interface, + 'service_id': self._neutron_id}) + + @mock.patch('os_client_config.make_shade') + def test_endpoint_interface(self, *args): + args[0].return_value.search_services.return_value = [ + munch.Munch(id=self._neutron_id)] + args[0].return_value.search_endpoints.return_value = [munch.Munch()] + self.assertEqual(self.test.run(), testcase.TestCase.EX_RUN_ERROR) + args[0].return_value.search_services.assert_called_once_with('neutron') + args[0].return_value.search_endpoints.assert_called_once_with( + filters={'interface': self._os_interface, + 'service_id': self._neutron_id}) + + @mock.patch('os_client_config.make_shade') def _test_no_env_var(self, var, *args): del os.environ[var] self.assertEqual(self.test.run(), testcase.TestCase.EX_RUN_ERROR) args[0].assert_called_once_with() - args[1].assert_called_once_with(mock.ANY, 'network') - @mock.patch('snaps.openstack.utils.keystone_utils.get_endpoint', - return_value=ODLTesting._neutron_url) - @mock.patch('functest.opnfv_tests.openstack.snaps.snaps_utils.' - 'get_credentials') + @mock.patch('os_client_config.make_shade') def _test_missing_value(self, *args): self.assertEqual(self.test.run(), testcase.TestCase.EX_RUN_ERROR) args[0].assert_called_once_with() - args[1].assert_called_once_with(mock.ANY, 'network') - @mock.patch('snaps.openstack.utils.keystone_utils.get_endpoint', - return_value=ODLTesting._neutron_url) - @mock.patch('functest.opnfv_tests.openstack.snaps.snaps_utils.' - 'get_credentials') + @mock.patch('os_client_config.make_shade') def _test_run(self, status=testcase.TestCase.EX_OK, exception=None, *args, **kwargs): + args[0].return_value.search_services.return_value = [ + munch.Munch(id=self._neutron_id)] + args[0].return_value.search_endpoints.return_value = [ + munch.Munch(url=self._neutron_url)] odlip = kwargs['odlip'] if 'odlip' in kwargs else '127.0.0.3' odlwebport = kwargs['odlwebport'] if 'odlwebport' in kwargs else '8080' odlrestconfport = (kwargs['odlrestconfport'] @@ -313,14 +380,18 @@ class ODLRunTesting(ODLTesting): osprojectdomainname=self._os_projectdomainname, osuserdomainname=self._os_userdomainname) args[0].assert_called_once_with() - args[1].assert_called_once_with(mock.ANY, 'network') + args[0].return_value.search_services.assert_called_once_with('neutron') + args[0].return_value.search_endpoints.assert_called_once_with( + filters={'interface': os.environ.get("OS_INTERFACE", "public"), + 'service_id': self._neutron_id}) - @mock.patch('snaps.openstack.utils.keystone_utils.get_endpoint', - return_value=ODLTesting._neutron_url) - @mock.patch('functest.opnfv_tests.openstack.snaps.snaps_utils.' - 'get_credentials') + @mock.patch('os_client_config.make_shade') def _test_multiple_suites(self, suites, status=testcase.TestCase.EX_OK, *args, **kwargs): + args[0].return_value.search_endpoints.return_value = [ + munch.Munch(url=self._neutron_url)] + args[0].return_value.search_services.return_value = [ + munch.Munch(id=self._neutron_id)] odlip = kwargs['odlip'] if 'odlip' in kwargs else '127.0.0.3' odlwebport = kwargs['odlwebport'] if 'odlwebport' in kwargs else '8080' odlrestconfport = (kwargs['odlrestconfport'] @@ -336,10 +407,13 @@ class ODLRunTesting(ODLTesting): osprojectdomainname=self._os_projectdomainname, osuserdomainname=self._os_userdomainname) args[0].assert_called_once_with() - args[1].assert_called_once_with(mock.ANY, 'network') + args[0].return_value.search_services.assert_called_once_with('neutron') + args[0].return_value.search_endpoints.assert_called_once_with( + filters={'interface': os.environ.get("OS_INTERFACE", "public"), + 'service_id': self._neutron_id}) def test_exc(self): - with mock.patch('snaps.openstack.utils.keystone_utils.get_endpoint', + with mock.patch('os_client_config.make_shade', side_effect=Exception()): self.assertEqual(self.test.run(), testcase.TestCase.EX_RUN_ERROR) @@ -379,6 +453,34 @@ class ODLRunTesting(ODLTesting): odlip=self._sdn_controller_ip, odlwebport=self._odl_webport) + def test_without_os_interface(self): + del os.environ["OS_INTERFACE"] + os.environ["SDN_CONTROLLER_IP"] = self._sdn_controller_ip + self._test_run(testcase.TestCase.EX_OK, None, + odlip=self._sdn_controller_ip, + odlwebport=self._odl_webport) + + def test_os_interface_public(self): + os.environ["OS_INTERFACE"] = "public" + os.environ["SDN_CONTROLLER_IP"] = self._sdn_controller_ip + self._test_run(testcase.TestCase.EX_OK, None, + odlip=self._sdn_controller_ip, + odlwebport=self._odl_webport) + + def test_os_interface_internal(self): + os.environ["OS_INTERFACE"] = "internal" + os.environ["SDN_CONTROLLER_IP"] = self._sdn_controller_ip + self._test_run(testcase.TestCase.EX_OK, None, + odlip=self._sdn_controller_ip, + odlwebport=self._odl_webport) + + def test_os_interface_admin(self): + os.environ["OS_INTERFACE"] = "admin" + os.environ["SDN_CONTROLLER_IP"] = self._sdn_controller_ip + self._test_run(testcase.TestCase.EX_OK, None, + odlip=self._sdn_controller_ip, + odlwebport=self._odl_webport) + def test_suites(self): os.environ["SDN_CONTROLLER_IP"] = self._sdn_controller_ip self._test_multiple_suites( diff --git a/functest/tests/unit/openstack/rally/test_rally.py b/functest/tests/unit/openstack/rally/test_rally.py index 970e5c4f4..3ef90c44e 100644 --- a/functest/tests/unit/openstack/rally/test_rally.py +++ b/functest/tests/unit/openstack/rally/test_rally.py @@ -85,15 +85,16 @@ class OSRallyTesting(unittest.TestCase): None) def test_task_succeed_fail(self): - json_raw = json.dumps([None]) + json_raw = json.dumps({}) self.assertEqual(self.rally_base.task_succeed(json_raw), False) - json_raw = json.dumps([{'result': [{'error': ['test_error']}]}]) + json_raw = json.dumps({'tasks': [{'status': 'crashed'}]}) self.assertEqual(self.rally_base.task_succeed(json_raw), False) def test_task_succeed_success(self): - json_raw = json.dumps('') + json_raw = json.dumps({'tasks': [{'status': 'finished', + 'pass_sla': True}]}) self.assertEqual(self.rally_base.task_succeed(json_raw), True) @@ -214,8 +215,6 @@ class OSRallyTesting(unittest.TestCase): @mock.patch('functest.opnfv_tests.openstack.rally.rally.RallyBase.' '_build_task_args', return_value={}) @mock.patch('functest.opnfv_tests.openstack.rally.rally.RallyBase.' - '_append_summary') - @mock.patch('functest.opnfv_tests.openstack.rally.rally.RallyBase.' 'get_task_id', return_value=None) @mock.patch('functest.opnfv_tests.openstack.rally.rally.RallyBase.' 'get_cmd_output', return_value='') @@ -225,7 +224,8 @@ class OSRallyTesting(unittest.TestCase): @mock.patch('functest.opnfv_tests.openstack.rally.rally.LOGGER.error') def test_run_task_taskid_missing(self, mock_logger_error, *args): # pylint: disable=unused-argument - self.rally_base._run_task('test_name') + with self.assertRaises(Exception): + self.rally_base._run_task('test_name') text = 'Failed to retrieve task_id, validating task...' mock_logger_error.assert_any_call(text) @@ -237,8 +237,6 @@ class OSRallyTesting(unittest.TestCase): @mock.patch('functest.opnfv_tests.openstack.rally.rally.RallyBase.' '_build_task_args', return_value={}) @mock.patch('functest.opnfv_tests.openstack.rally.rally.RallyBase.' - '_append_summary') - @mock.patch('functest.opnfv_tests.openstack.rally.rally.RallyBase.' 'get_task_id', return_value='1') @mock.patch('functest.opnfv_tests.openstack.rally.rally.RallyBase.' 'get_cmd_output', return_value='') @@ -250,13 +248,30 @@ class OSRallyTesting(unittest.TestCase): @mock.patch('functest.opnfv_tests.openstack.rally.rally.os.makedirs') @mock.patch('functest.opnfv_tests.openstack.rally.rally.LOGGER.info') @mock.patch('functest.opnfv_tests.openstack.rally.rally.LOGGER.error') - def test_run_task_default(self, mock_logger_error, mock_logger_info, - *args): + @mock.patch('functest.opnfv_tests.openstack.rally.rally.RallyBase.' + '_save_results') + def test_run_task_default(self, mock_save_res, *args): # pylint: disable=unused-argument self.rally_base._run_task('test_name') - text = 'Test scenario: "test_name" OK.\n' - mock_logger_info.assert_any_call(text) - mock_logger_error.assert_not_called() + mock_save_res.assert_called() + + @mock.patch('__builtin__.open', mock.mock_open()) + @mock.patch('functest.opnfv_tests.openstack.rally.rally.RallyBase.' + 'task_succeed', return_value=True) + @mock.patch('functest.opnfv_tests.openstack.rally.rally.RallyBase.' + 'get_cmd_output', return_value='') + @mock.patch('functest.opnfv_tests.openstack.rally.rally.os.path.exists', + return_value=True) + @mock.patch('functest.opnfv_tests.openstack.rally.rally.subprocess.Popen') + @mock.patch('functest.opnfv_tests.openstack.rally.rally.os.makedirs') + @mock.patch('functest.opnfv_tests.openstack.rally.rally.LOGGER.info') + @mock.patch('functest.opnfv_tests.openstack.rally.rally.LOGGER.debug') + @mock.patch('functest.opnfv_tests.openstack.rally.rally.RallyBase.' + '_append_summary') + def test_save_results(self, mock_summary, *args): + # pylint: disable=unused-argument + self.rally_base._save_results('test_name', '1234') + mock_summary.assert_called() def test_prepare_env_testname_invalid(self): self.rally_base.TESTS = ['test1', 'test2'] @@ -473,15 +488,31 @@ class OSRallyTesting(unittest.TestCase): mock_prep_env.assert_called() def test_append_summary(self): - text = '[{"result":[{"error":[]},{"error":["err"]}],' \ - '"full_duration": 17.312026}]' + text = '{"tasks": [{"subtasks": [{"workloads": [{"full_duration": ' \ + '1.23,"data": [{"error": []}]}]},{"workloads": ' \ + '[{"full_duration": 2.78, "data": [{"error": ["err"]}]}]}]}]}' self.rally_base._append_summary(text, "foo_test") self.assertEqual(self.rally_base.summary[0]['test_name'], "foo_test") - self.assertEqual(self.rally_base.summary[0]['overall_duration'], - 17.312026) + self.assertEqual(self.rally_base.summary[0]['overall_duration'], 4.01) self.assertEqual(self.rally_base.summary[0]['nb_tests'], 2) self.assertEqual(self.rally_base.summary[0]['nb_success'], 1) + def test_is_successful_false(self): + with mock.patch('__builtin__.super') as mock_super: + self.rally_base.summary = [{"task_status": True}, + {"task_status": False}] + self.assertEqual(self.rally_base.is_successful(), + testcase.TestCase.EX_TESTCASE_FAILED) + mock_super(rally.RallyBase, self).is_successful.assert_not_called() + + def test_is_successful_true(self): + with mock.patch('__builtin__.super') as mock_super: + mock_super(rally.RallyBase, self).is_successful.return_value = 424 + self.rally_base.summary = [{"task_status": True}, + {"task_status": True}] + self.assertEqual(self.rally_base.is_successful(), 424) + mock_super(rally.RallyBase, self).is_successful.assert_called() + if __name__ == "__main__": logging.disable(logging.CRITICAL) |